By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,836 Members | 2,028 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,836 IT Pros & Developers. It's quick & easy.

Figure out when mouse cursor enters/leaves form

P: n/a
Hello,

I have tried this using the MouseEnter/MouseLeave events. However these
events do not really refer to the rectangular shape of the form, but
the client area (form area minus children areas). This means that if
the mouse is currently inside the form's client area and it enters a
child, a MouseLeave event will be generated on the form.

One little trick to overcome this is to do a point-in-rectangle test
inside the MouseLeave handler:

if (!Bounds.Contains(MousePosition))
{
// mouse really left the form
}
This however doesn't always work, for example if you have another
window on top of yours, because that window's area will be treated just
like a child area.

Anyone knows how to do this cleanly?

Thanks in advance,
Cosmin.

Oct 16 '06 #1
Share this Question
Share on Google+
4 Replies


P: n/a

cb******@gmail.com wrote:
Hello,

I have tried this using the MouseEnter/MouseLeave events. However these
events do not really refer to the rectangular shape of the form, but
the client area (form area minus children areas). This means that if
the mouse is currently inside the form's client area and it enters a
child, a MouseLeave event will be generated on the form.

One little trick to overcome this is to do a point-in-rectangle test
inside the MouseLeave handler:

if (!Bounds.Contains(MousePosition))
{
// mouse really left the form
}
This however doesn't always work, for example if you have another
window on top of yours, because that window's area will be treated just
like a child area.

Anyone knows how to do this cleanly?

Thanks in advance,
Cosmin.
You could iterate through the control tree and add MouseEnter and
MouseLeave events to every single control. Then do the same for every
single ControlAdded and ControlRemoved, adding/removing all four event
bindings to every new control added anywhere in the tree. Just recurse
through the control.Controls collection.

Thus, you know which control the mouse is pointing at at any given
time.... the only worry is that I don't know what order things happen
in - when a mouse transitions from one control to the next, if it
"Leaves" control X before it "enters" control Y, there will be a
momentary "gap" where your app thinks it isn't pointing at the form.

If "Leave" happens first, then I guess you just use a hack with a
timer. The timer runs as fast as is reasonable for good UI feedback -
when, in two sequential cycles, the mouse is outside of all controls,
then you accept that it has left the form. If it ever inside of the
set of all controls, then it is still inside the form. Hacky, but it
should work.

Oct 16 '06 #2

P: n/a
Seems a bit overkill just just for this... :|

Martin Z wrote:
cb******@gmail.com wrote:
Hello,

I have tried this using the MouseEnter/MouseLeave events. However these
events do not really refer to the rectangular shape of the form, but
the client area (form area minus children areas). This means that if
the mouse is currently inside the form's client area and it enters a
child, a MouseLeave event will be generated on the form.

One little trick to overcome this is to do a point-in-rectangle test
inside the MouseLeave handler:

if (!Bounds.Contains(MousePosition))
{
// mouse really left the form
}
This however doesn't always work, for example if you have another
window on top of yours, because that window's area will be treated just
like a child area.

Anyone knows how to do this cleanly?

Thanks in advance,
Cosmin.

You could iterate through the control tree and add MouseEnter and
MouseLeave events to every single control. Then do the same for every
single ControlAdded and ControlRemoved, adding/removing all four event
bindings to every new control added anywhere in the tree. Just recurse
through the control.Controls collection.

Thus, you know which control the mouse is pointing at at any given
time.... the only worry is that I don't know what order things happen
in - when a mouse transitions from one control to the next, if it
"Leaves" control X before it "enters" control Y, there will be a
momentary "gap" where your app thinks it isn't pointing at the form.

If "Leave" happens first, then I guess you just use a hack with a
timer. The timer runs as fast as is reasonable for good UI feedback -
when, in two sequential cycles, the mouse is outside of all controls,
then you accept that it has left the form. If it ever inside of the
set of all controls, then it is still inside the form. Hacky, but it
should work.
Oct 16 '06 #3

P: n/a
Why? It might prove to be a performance killer - testing will show
that. But semantically, it's simple. Code one event-binding function
that sets up the events and applies itself to all children - then make
the reverse. This pair is what is called by the ControlAdded and
ControlRemoved handlers. Then you just have the MouseEnter write to a
shared "CurrentMouseControl" member - and the MouseLeave checks to make
sure that it's not leaving the "CurrentMouseControl" member (assuming
the MouseLeave-after-MouseEnter behaviour that I'm hoping for).

The complex, wasteful, overkill solution is only needed in the case
that Leave happens first.

cb******@gmail.com wrote:
Seems a bit overkill just just for this... :|

Martin Z wrote:
cb******@gmail.com wrote:
Hello,
>
I have tried this using the MouseEnter/MouseLeave events. However these
events do not really refer to the rectangular shape of the form, but
the client area (form area minus children areas). This means that if
the mouse is currently inside the form's client area and it enters a
child, a MouseLeave event will be generated on the form.
>
One little trick to overcome this is to do a point-in-rectangle test
inside the MouseLeave handler:
>
if (!Bounds.Contains(MousePosition))
{
// mouse really left the form
}
>
>
This however doesn't always work, for example if you have another
window on top of yours, because that window's area will be treated just
like a child area.
>
Anyone knows how to do this cleanly?
>
Thanks in advance,
Cosmin.
You could iterate through the control tree and add MouseEnter and
MouseLeave events to every single control. Then do the same for every
single ControlAdded and ControlRemoved, adding/removing all four event
bindings to every new control added anywhere in the tree. Just recurse
through the control.Controls collection.

Thus, you know which control the mouse is pointing at at any given
time.... the only worry is that I don't know what order things happen
in - when a mouse transitions from one control to the next, if it
"Leaves" control X before it "enters" control Y, there will be a
momentary "gap" where your app thinks it isn't pointing at the form.

If "Leave" happens first, then I guess you just use a hack with a
timer. The timer runs as fast as is reasonable for good UI feedback -
when, in two sequential cycles, the mouse is outside of all controls,
then you accept that it has left the form. If it ever inside of the
set of all controls, then it is still inside the form. Hacky, but it
should work.
Oct 16 '06 #4

P: n/a
To hook up the event handlers try something like

SetEventHandlers(this, new EventHandler(Form1_MouseEnter), new
EventHandler(Form1_MouseLeave));
..
..
..
private void SetEventHandlers(Control control, EventHandler mouseEnter,
EventHandler mouseLeave)
{
control.MouseEnter += mouseEnter;
control.MouseLeave += mouseLeave;

foreach (Control ctl in control.Controls)
{
SetEventHandlers(ctl, mouseEnter, mouseLeave);
}
}

Also, to check the non-client area (and the client area if you wish) you
could override WndProc.

// From WinUser.h
private const int WM_NCHITTEST = 0x0084;
private const int WM_MOUSEMOVE = 0x0200;
private const int WM_MOUSELEAVE = 0x02A3;
private const int WM_NCMOUSEMOVE = 0x00A0;
private const int WM_NCMOUSELEAVE = 0x02A2;

protected override void WndProc(ref Message m)
{
base.WndProc(ref m);

switch (m.Msg)
{
case WM_NCMOUSELEAVE:
// Your code here
break;
Oct 17 '06 #5

This discussion thread is closed

Replies have been disabled for this discussion.