There are two mouse-messages that are never received unless you explicitly instruct Windows to track the mouse movement. The first message is WM_MOUSELEAVE that is supposed to report that the mouse has left the client-area. The second is WM_MOUSEHOVER which is posted after hovering a certain amount of time over some area. To obtain one (or both) of these messages you need to call TrackMouseEvent() API which notifies the application when the mouse leaves the window or when the mouse hovers over an area for a while.
The next program illustrates how to implement a mouseover feature by drawing a box that turns black when you move the mouse over it. The basic idea is to use WM_ MOUSEMOVE to know when the mouse has moved in or out of the box. The only problem is that if the user moves the mouse quickly outside the window, you won't get a WM_ MOUSEMOVE. To implement a correct behavior of mouseover, you need to know when the mouse has left the window entirely.
The program doesn’t use the _MouseMove eventsub, but combines the mouseover-logic into the _Message eventsub, which receives all (posted) mouse messages. There are no event subs for WM_MOUSELEAVE and WM_MOUSEHOVER, so they have to be handled in a general event- sub. An alternative would be to handle the messages in _MessageProc, but its use is a bit more complicated. In addition, _Message doesn’t require any return values, so it serves our purpose best.
OpenW Center 1
Do
Sleep
Until Win_1 Is Nothing
Sub Win_1_Paint
Box 10, 10, 100, 100
EndSub
Sub Win_1_Message(hWnd%, Mess%, wParam%, lParam%)
Static Bool fTrackingMouse, fBoxHighLighted
Dim tme As TRACKMOUSEEVENT
Local Int mx, my
Switch Mess%
Case WM_MOUSEMOVE
' Track a mouseleave event. Results in a WM_MOUSELEAVE
' message when the mouse leaves the window.
If !fTrackingMouse ' set it only once
tme.cbSize = SizeOf(TRACKMOUSEEVENT)
tme.dwFlags = TME_LEAVE
tme.hwndTrack = Me.hWnd
fTrackingMouse = TrackMouseEvent(tme) != 0
EndIf
' If mouse is over the box start timer
mx = LoWord(lParam%), my = HiWord(lParam%)
If mx > 10 && mx < 100 && my > 10 && my < 100
tme.cbSize = SizeOf(TRACKMOUSEEVENT)
tme.dwFlags = TME_HOVER ' start timer
tme.hwndTrack = Me.hWnd
tme.dwHoverTime = HOVER_DEFAULT ' use default time
TrackMouseEvent(tme) ' now wait for WM_MOUSEHOVER
Else If fBoxHighLighted ' hilighted and not over box
Win_1.Invalidate 10, 10, 90, 90
fBoxHighLighted = False
EndIf
Case WM_MOUSELEAVE ' triggered by TrackMouseEvent
fTrackingMouse = False ' TrackMouseEvent not active anymore
If fBoxHighLighted ' redraw original box
Win_1.Invalidate 10, 10, 90, 90
fBoxHighLighted = False ' box is not highlighted
EndIf
Case WM_MOUSEHOVER ' triggered by TrackMouseEvent's timer
mx = LoWord(lParam%), my = HiWord(lParam%) ' mouse coordinates
If !fBoxHighLighted && mx > 10 && mx < 100 && my > 10 && my < 100
PBox 10, 10, 100, 100 ' highlight the box
fBoxHighLighted = True
EndIf
EndSwitch
EndSub
Public Const HOVER_DEFAULT = 0xFFFFFFFF
Type TRACKMOUSEEVENT
- DWord cbSize
- DWord dwFlags
- Handle hwndTrack
- DWord dwHoverTime
EndType
Declare Function TrackMouseEvent Lib "user32" Alias _
"TrackMouseEvent" (ByRef EventTrack As TRACKMOUSEEVENT) As Long
The _Message sub declares two static booleans, fTrackingMouse and fBoxHighLighted, that keep track of the current state of the mouseover-logic. (If I would have used the _MouseMove eventsub to initiate the mouse tracking the variables should have been declared global, I always try to avoid global variables as much as possible.)
When the first (of many) WM_MOUSEMOVE message is received, the TrackMouseEvent() API is used to set up a WM_MOUSELEAVE "one-shot" event. Exactly one and only one WM_MOUSELEAVE message will be posted to the window specified in the hwndTrack member of the TRACKMOUSEEVENT structure, when the mouse has left the client area.
Note - The message will be generated only once. The application must call the TrackMouseEvent API again in order for the system to generate another WM_MOUSELEAVE message. In addition, when the mouse pointer is not over the application, a call to TrackMouseEvent() will result in the immediate posting of a WM_MOUSELEAVE message.
When the mouse is over the box, the TrackMouseEvent() is used to start a timer that eventually posts the WM_MOUSEHOVER message. After receiving WM_MOUSEHOVER the box is highlighted if the mouse is still over the box. The fBoxHighLigted variable is set to indicate the state of the box. If the variable is set but the mouse is no longer over the box the area occupied by the box is invalidated so that it is redrawn eventually.
No comments:
Post a Comment