views:

51

answers:

2

Hi, I have a form where I want buttons at the very bottom edge of the form, with no gap to the border. These buttons shall be "auto-hide", so they only show when the mouse is in for example the lower 20 pixels of the form. So I use the MouseMove event to trigger this, like code below. However, if mouse leaves the form across the bottom edge, where the buttons are, then the buttons will obviously remain. But I want them to hide. So I need for this purpose to hide the buttons by some other event. Hence I try to hide them in the form's MouseLeave event. But this makes the buttons unclickable and in an erratic state, flashing on and off when the mouse goes over the button.. Why is this? And how can I avoid this problem to get such autohide feature?

  Private Sub ZgScale_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseMove

    If e.Y > Me.ClientSize.Height - 30 Then
        Button1.Visible = True
    Else
        Button1.Visible = False
    End If
End Sub

Private Sub ZgScale_MouseLeave(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.MouseLeave
    Button1.Visible = False
End Sub
+2  A: 

The MouseLeave event fires when the mouse is no longer directly on that control (or form).
If the mouse moves on to a child control, the event will fire.

You need to check whether the mouse is no longer on the form, like this:

If Not Me.ClientRectangle.Contains(Me.PointToClient(e.Location)) Then
    Button1.Visible = False
End If

EDIT: Fixed

SLaks
hmm.. but where to put this code?
bretddog
@bretddog: Try it now. I was mistakenly also checking the window frame.
SLaks
Thanks.. I think the problem is that the MouseMove event doesn't fire when mouse left the form.. so where can I put your code?
bretddog
In `MouseLeave`.
SLaks
ah.. yes. of course.. Seems to work almost.. only when I move outside across the button, the button remains.. maybe I need to add it to buttonLeave also..
bretddog
Yes; handle `Button1.MouseLeave` and add the same logic (calling `Me.PointToClient(MousePosition)` since `e.Location` is relative to the button)
SLaks
Yes.. that helped.. now it hides when I leave mouse across button too (Since button is exactly at the edge).. Still it will be a problem, as I want like 5 buttons directly next to eachother (no gap).. And I don't want to hide them when mouse leaves a button sideways.. hmmm.. i must think.. (Yes I used Mouseposition :) )
bretddog
If you're using `MousePosition`, that should work perfectly. Use the debugger.
SLaks
oh.. yes it does.. my mistake. Thanks a lot! I really needed that :)
bretddog
@brettdog:Then you should accept this answer by clicking the hollow check.
SLaks
Ah. cheers. I didn't know that. I'm new here. :)
bretddog
+1  A: 

Windows has direct support built-in for this scenario. Also exposed in Windows Forms and WPF. Once you get the MouseMove event, set the Capture property on the control to True. That forces all mouse messages to be directed to the control, even if the mouse moves outside of the control window.

Once you see it moving outside of the control bounds, set Capture back to false and hide your control. Beware that capture is turned off when the user clicks the mouse so you'll probably have to turn it back on afterwards. Although it should be automatic, you'll get another MouseMove event. Could fail if the user moves the mouse really fast.

Hans Passant
Interesting.. If I understand correctly I should let the form or the underlying control capture the mouse, instead of the buttons (?) I see.. But then what if I scroll the mouse on top of a button, will the button get that mouse event ?
bretddog
Oh.. that's not a button event.. sorry. but for example a mouseLeave event of the button. I will not get it with this solution? Because I need to do something on such event. Like change color of button.
bretddog
It gets murky when you have multiple controls that you want to make disappear. Coordinating their MouseEnter/Leave events doesn't work, it is always defeated by the user moving the mouse really fast. The mouse is sampled, it doesn't provide a continuous stream of pixel positions. The only real fix then is to use a Timer, 200 msec is okay, and look at the Mouse.Position. You'll need Control.PointToClient.
Hans Passant
Thanks! It's good to know about the Capture property. However it seems the solution given by SLaks will be the best here for this situation. I simply check the MouseMove event of the underlying control, and also I make a MouseMove handler registered to all the buttons located at this lower edge, which calls the method that hides what I want to hide. Then I should be covered, and not lose any functionality also. At least it seems fail proof so far to me.
bretddog
And this works when you move the mouse outside of the form quickly an circle around?
Hans Passant
Yes, I'm not able to make it fail no matter how fast or strange I move. Only way to make it fail is if I leave the form through/from a control which I have not subscribed to it's MouseLeave event (to call the hide method). Then obviously the stuff will not be hidden. I guess when the MouseLeave events get fired, the MousePosition is already outside the form, hence the method (IF) will trigger in any case.
bretddog