Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Detect when mouse leaves control region

Status
Not open for further replies.

phinoppix

Programmer
Jul 24, 2002
437
US
I am making my own flat command button and I'm stopped on how to manage mouse movement. Similar to explorer buttons when you hover them, the borders appear when it enters the button region and disappears otherwise.

I've made some reading on callbacks and some API functions and came across with PeekMessage().

What I thought over is I monitor my control's messages, particularly mouse's, and wait for WM_MOUSELEAVE.

At the PeekMessage line, it always returns zero.

Here's a draft of my 'project'

At Usercontrol_ReadProperties() event,
Code:
If Ambient.Usermode then
  If mbTimerInit Then
    mlngID = SetTimer(UserControl.hWnd, 0&, 200, _
                       AddressOf TimeProc)
    mbTimerInit = True  'module level boolean
  End If
End If

At Module1,
Code:
Option Explicit

Private Type POINTAPI
        X As Long
        Y As Long
End Type
Private Type MSG
    hwnd As Long
    message As Long
    wParam As Long
    lParam As Long
    time As Long
    pt As POINTAPI
End Type
Public Declare Function SetTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
Public Declare Function KillTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long) As Long
Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Private Declare Function WindowFromPoint Lib "user32" (ByVal xPoint As Long, ByVal yPoint As Long) As Long
Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare Function PeekMessage Lib "user32" Alias "PeekMessageA" (lpMsg As MSG, ByVal hwnd As Long, ByVal wMsgFilterMin As Long, ByVal wMsgFilterMax As Long, ByVal wRemoveMsg As Long) As Long
Private Const WM_QUIT = &H12
Private Const PM_NOREMOVE = &H0

Private Const WM_USER = &H400
Private Const WM_MOUSELEAVE As Long = WM_USER + 2
Private Const WM_MOUSEFIRST = &H200
Private Const WM_MOUSELAST = &H209


Private Const CLASSNAME = "ThunderUserControlDC"
Private Const CLASSSIZE = 4096
Sub Main()

End Sub
Public Sub TimerProc(ByVal hwnd As Long, ByVal uiMsg As Long, ByVal idEvent As Long, ByVal dwTime As Long)
    'Peek message for my usercontrol defined by hwnd
    Dim plng_val As Long
    Dim lp_MSG As MSG
    plng_val = PeekMessage(lp_MSG, hwnd, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE)
    If plng_val = 0 Then  'at this point, it failed
        Debug.Print hwnd, lp_MSG.message
        Exit Sub
    End If
    
    'test for mouse message
    Select Case lp_MSG.message
        Case WM_QUIT
            Exit Sub
        Case WM_MOUSELEAVE
            'Debug.Print "Elvis has left the building"
        Case Else
            'Debug.Print "none"
    End Select
End Sub

TIA [peace]
 
You do not need to do so complicated:

When the mouse is over the area covered by your button, WM_MOUSEMOVE's will be generated (which translate into MouseMoves or something like that). Call the API TrackMouseEvent and set this up so the WM_MOUSELEAVE will be generated as soon as the mouse moves out of the client area of your button (mousetracking will be automatically canceled when this happens). WM_MOUSELEAVE will NOT be generated if you do not track the mouse. Because the WM_MOUSELEAVE will not be translated to a message that can be handled natively by VB, you will have to hook the windows procedure of your button (SetWindowsHookEx) and handle the message there. Now just set and reset a flag indicating that tracking is on or off (so you won't be calling TrackMouseEvent over and over again) and you're done.


Also:
PeekMessage returns 0 if there are NO messages in the queue, this is probably why it fails at the point you mentioned....
Rum am Morgen vorkommt Kummer und Sorgen... Cheers !

Mr. Rum
 
PraveenMenom, tnx for the reply. But I was hoping for code snippets or something, for reference.

MrRum, pls correct me if I'm wrong. PeekMessage would work only if I will tell VB to actually watch Win msgs (SetWindowsHookEx), that's why it always return 0?

Forgot to tell you also, am VERY novice to API, particularly callbacks and hooking things.

Do you have useful and easy-to-understand [smile] links regarding this topic? I browsed MSDN Lib but most samples are in C, and I don't know anything bout C.

TIA [peace]
 
I think what Mr Rum is referring to is this code snippet:

If plng_val = 0 Then 'at this point, it failed
Debug.Print hwnd, lp_MSG.message
Exit Sub
End If

Here you are trying to print the message to the debug window, while ter is no message to print. The PeekMessage returns 0 if there were no messages in the queue. If you want to do that you must go If plng_val <> 0 etc.


And as for the WM_MOUSELEAVE:
This message will NOT be natively handled by VB (you have no handler for it in the dropdown list of your form, do you?). That's why you probably have to hook the windows proc so that you can handle the message that way.

And you're right about the code snippets being in C. This is because in C it's so very easy to use the APIs and in VB you rarely use them (that is, being a VB programmer that is satisfied with the functionality offered by the language itself). But since you now want to have functionality offered by the Windows platform which is not natively supported by VB, you will have to learn a bit about APIs. I am afraid that there is no way around that for you.....



Greetings,
Rick
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top