|
-
Jan 26th, 2010, 11:10 AM
#15
Re: how do i show an image when mouse is over a menu item?
Just because I love puzzles, this is a good solution, but has one drawback addressed at bottom of this post.
The fix is to locate the menu immediately, test whether the mouse X,Y coords are within the window bounds, and testing if the menu is visible or not. Seems to work really well for mouse "hover" over a menu selection.
Code:
Option Explicit
Private Declare Function GetCursorPos Lib "user32.dll" (ByRef lpPoint As POINTAPI) As Long
Private Declare Function WindowFromPoint Lib "user32.dll" (ByVal xPoint As Long, ByVal yPoint As Long) As Long
Private Declare Function GetClassName Lib "user32.dll" Alias "GetClassNameA" (ByVal hWnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
Private Declare Function GetWindowRect Lib "user32.dll" (ByVal hWnd As Long, ByRef lpRect As RECT) As Long
Private Declare Function ScreenToClient Lib "user32.dll" (ByVal hWnd As Long, ByRef lpPoint As POINTAPI) As Long
Private Declare Function IsWindowVisible Lib "user32.dll" (ByVal hWnd As Long) As Long
Private Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Type POINTAPI
X As Long
Y As Long
End Type
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private myMenuHwnd As Long
Private Sub mnuMain_Click()
' when menu opens, start timer
Me.Caption = "Waiting for menu selection" ' testing purposes
DoEvents ' should allow menu to appear
myMenuHwnd = FindWindow("#32768", vbNullString)
Timer1.Tag = "-1"
Timer1.Interval = 100
Timer1.Enabled = True
End Sub
Private Sub Timer1_Timer()
Dim mPT As POINTAPI, sBuffer As String
Dim wRect As RECT, mIndex As Long
Dim nrMenuItems As Long
GetCursorPos mPT
If myMenuHwnd = 0& Then
myMenuHwnd = WindowFromPoint(mPT.X, mPT.Y)
sBuffer = String$(6, vbNullChar)
Call GetClassName(myMenuHwnd, sBuffer, 7)
If sBuffer <> "#32768" Then myMenuHwnd = 0&
ElseIf IsWindowVisible(myMenuHwnd) = 0& Then
Me.Caption = "Menu closed" ' testing purposes
Timer1.Enabled = False
myMenuHwnd = 0&
End If
If myMenuHwnd Then
GetWindowRect myMenuHwnd, wRect
If mPT.Y > wRect.Top And mPT.Y < wRect.Bottom Then
If mPT.X > wRect.Left And mPT.X < wRect.Right Then
ScreenToClient myMenuHwnd, mPT
nrMenuItems = 3 ' I only used 3 for my test
mIndex = mPT.Y \ ((wRect.Bottom - wRect.Top) \ nrMenuItems)
If mIndex <> Val(Timer1.Tag) Then
Timer1.Tag = mIndex
Me.Caption = "over menu item " & mIndex + 1 ' testing purposes
End If
End If
End If
End If
End Sub
Downside. Does not deal with user moving up/down menu items via the keyboard. Can be overcome with a keybd hook (like subclassing) or another timer testing keyboard for strokes (GetAsyncKeyState API for example)
Edited:
Other potential issues if they apply:
1. If menu is large and eventually scrolls; all bets are off and will require a lot more work
2. If menu opens any contained submenus; needs more work to stop timer when submenu opens & restart timer when submenu closes
Subclassing is the correct way to do what you want and all issues will be overcome; but as mentioned before, subclassing requires some practice and has zero-tolerance for errors. Makeshift workarounds rarely work as well, can be buggy, and often are less efficient than the "correct" way. Just FYI.
Last edited by LaVolpe; Jan 26th, 2010 at 12:17 PM.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|