3

I have a button and upon mouseenter, a little form pops up, and upon mouseleave of the button, the little form disappears. I am needing this form to not accept any mouse events, in other words, be "invisible" to the mouse.

The problem is, the form pops up under the mouse, which triggers the mouseleave event for the button. I know there are other ways to get around this, but i'm needing the form to hide when the mouse leaves the original button that triggered the form, and I also need the form to appear underneath the mouse.

So how can I make the little pop-up form invisible to mouse-events, so that it doesn't cause the "mouse leave" event to trigger for the button?

The popup is of type "Form". Here is the mouseEnter and mouseLeave code that triggers showing and hiding the form:

private void btnPatientSearch_MouseEnter(object sender, EventArgs e)
        {
                _currentPatientInfo = new PatientInfo()
                {
                    MdiParent = this.MdiParent
                };
                _currentPatientInfo.Show();
                _currentPatientInfo.Location = new Point(181, 9);
            }
        }

        private void btnPatientSearch_MouseLeave(object sender, EventArgs e)
        {
            if (_currentPatientInfo == null) return;
            _currentPatientInfo.Hide();
            _currentPatientInfo = null;
        }
Tyler Jones
  • 1,283
  • 4
  • 18
  • 38
  • is the pop-up invisible or is it drawn at the pointer? When you look at the form1.designer.cs where does it have the box being drawn. Or better yet, can you modify post and add the auto generated code for the pop-up? Also what is it? is it a panel? Can you post the mouse event for the button as well? – Nyra Jun 11 '14 at 19:36
  • Okay, i added the mouseenter and mouseleave code. The designer generated code is quite a lot. – Tyler Jones Jun 11 '14 at 19:44
  • Add btnPatientSearch.Capture = true; in the MouseEnter event handler. – Hans Passant Jun 11 '14 at 19:47
  • Possible duplicate: http://stackoverflow.com/questions/19115578/how-to-suppress-global-mouse-click-events-from-windows – Bayeni Jun 11 '14 at 19:49
  • @Bayeni it's definitely not a duplicate of that question. I have no interest in blocking all mouse input for my entire operating system. – Tyler Jones Jun 11 '14 at 19:53
  • why would you need to write a mouseleave event for the button if at all, you all you would need is to close/hide the form? – HappyLee Jun 11 '14 at 19:54
  • @Hans Passant - I tried that, but then the button retains mouse control even after leaving the button with the mouse. How could i still use the mouseleave event if i use the "capture" property of the button? – Tyler Jones Jun 11 '14 at 19:55
  • @HappyLee I need the form to auto-hide when the mouse leaves the button. I do not want the user to have to close the form. Think along the lines of a tooltip. – Tyler Jones Jun 11 '14 at 19:55
  • Use the MouseMove event, you'll see it moving outside of the button's DisplayRectangle. – Hans Passant Jun 11 '14 at 19:56
  • okay got it. well in the case, MouseMove event is where you could write your logic. – HappyLee Jun 11 '14 at 19:59
  • @HansPassant - Okay, it works to check the display rectangle during mouse move after capturing the mouse. However, this seems like it could have side effects. If i set "enabled" to false on the pop-up form, it does exactly what i'm wanting, but all the controls become greyed out, which i don't want. Is there no way to mimic the behavior of "enabled = false" without greying out everything? – Tyler Jones Jun 11 '14 at 20:11
  • 4
    Focus on creating a usable user interface. Nothing you've been doing has been making any sense, you of course want to make sure that this form never overlaps the button. It also strongly sounds like this needs to be a tooltip. – Hans Passant Jun 11 '14 at 20:22
  • @TylerJones I don't think he meant to come across that way- he's been very helpful and patient in the past for me. I was going to mention same idea though (tooltip). Could you explain the situation a little clearer? It does, from the description, seem like you are overkilling this by showing a form. If you think about it, the point of the form is to provide user interaction. So if it disappears whenever you move mouse off a button somewhere else, how will you ever interact with it? Can you describe what you are trying to do? there might be a better solution you are unaware of. – Nyra Jun 11 '14 at 20:40
  • @alykins - Yes, a tooltip is the basic idea of what I'm needing to do, I just need a lot more to be displayed than just text, and I need to have control over how the information is presented. The form should not allow any user input at all. This type of thing is so ridiculously simple on so many other platforms, i just thought there'd a simple switch like "enableMouseInput = false". Does that make sense? – Tyler Jones Jun 11 '14 at 20:50
  • Yes and no- I don't typically do GUI coding. Can't you use the ToolTip class? What about that object isn't working for you? It might be easier to figure out what is not working for the ToolTip. – Nyra Jun 11 '14 at 21:14
  • @HansPassant - You want to form your comments as an answer so I can accept it? Using Capture + a mousemove event seems to be the only way to accomplish what i'm trying to do. – Tyler Jones Jun 11 '14 at 21:16
  • @TylerJones I see two problems here. First, you could achieve this much better by `userControl` instead of form. Second, when you create form and then hide and don't dispose it, you making a mess in memory. Popup forms should be sued with `using` so they can be disposed. Another way, to do this is if you actually add the new popup form to your main form control collection, you will get a movable object. YOu can open it at mouse location, so it covers the button and forse user to close it before user can continue back to button – T.S. Jun 11 '14 at 21:32

1 Answers1

1

Inherit your popup form from the following form class. This code is using some p/invokes and not tested, but it should work.

public class PopupForm : Form
{
  private const int WS_BORDER = 0x00800000;
  private const int WS_POPUP = unchecked((int)0x80000000);

  private const int WS_EX_TOPMOST = 0x00000008;
  private const int WS_EX_NOACTIVATE = 0x08000000;

  private const int WM_MOUSEACTIVATE = 0x0021;
  private const int MA_NOACTIVATEANDEAT = 4;

  private static readonly IntPtr HWND_TOPMOST = (IntPtr)(-1);

  private const int SWP_NOSIZE = 0x0001;
  private const int SWP_NOMOVE = 0x0002;
  private const int SWP_NOACTIVATE = 0x0010;

  [DllImport("user32.dll")]
  [return: MarshalAs(UnmanagedType.Bool)]
  private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter,
    int X, int Y, int cx, int cy, int uFlags);

  public PopupForm()
  {
    SetStyle(ControlStyles.Selectable, false);
    FormBorderStyle = FormBorderStyle.None;
    StartPosition = FormStartPosition.Manual;
    ShowInTaskbar = false;
    Visible = false;
  }

  protected override CreateParams CreateParams
  {
    get
    {
      CreateParams cp = base.CreateParams;
      cp.Style |= WS_POPUP | WS_BORDER;
      cp.ExStyle |= WS_EX_TOPMOST | WS_EX_NOACTIVATE;
      return cp;
    }
  }

  protected override bool ShowWithoutActivation
  {
    get { return true; }
  }

  protected override void WndProc(ref Message m)
  {
    if (m.Msg == WM_MOUSEACTIVATE)
    {
      OnClick(EventArgs.Empty);
      m.Result = (IntPtr)MA_NOACTIVATEANDEAT;
    }
    else
      base.WndProc(ref m);
  }

  public new void Show()
  {
    Windows.SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0,
      SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE);
    base.Show();
  }
}
arbiter
  • 9,447
  • 1
  • 32
  • 43