常见到某些软体,当Mouse进入其区域时,会启动某个行为,Mouse离开时,又有其他的 动作,例如Cool Bar,当Mouse移入时,Button会上升,离开时Button水变平面。 第一个想到的是在物件的MouseMove中设定进入的行为,这没有问题,但离开呢?有几 个想法:1.如果该物件在Form上,可以在Form的MouseMove上作离开的动作。2.於该物 件的MouseMove上Check是否Mouse的座标已在物件的边缘,若是则执行离开的动作。 但这两者,都会遇上一个问题,如果Mouse的移动很快,使得MouseMove的Event根本没 有在该物件或Form上面发生,那就不可行了;所以看来简单的问题又变复杂了,那只好 使用Mouse Hook来做。 Mouse Hook是拦截硬体所产生Mouse硬体的讯息,不管Mouse现在於何处,都会将Mouse的 讯息送往Hook Procedure,当然,一般情况下,是於该程式正处於Active的情况下 (Local Hook),讯息才会送往该Hook Procedure,如果别的程式所产生的Mouse讯息也要 进入该Hook Function时,那便得使用Remote Hook,而Remote Hook的方式,是要把Hook Procedure放在.Dll之中,而Local Hook只要把 Hook Procedure放在.Bas之中便可以了。 因挂上了Mouse Hook(Local),所以该程式执行时所有的Mouse 的讯息便会送往该Hook Function,而且有包含Mouse所在的座标(相对於Screen),於是我们可以Check Mouse 的座标,进而得知Mouse是否仍在物件范围。 Please Reference : 如何得知Mouse已离开某物件(二) '以下在.Bas Option Explicit Public Const WM_MOUSEMOVE = &H200 Public Const WH_MOUSE = 7 Type POINTAPI X As Long Y As Long End Type Type MOUSEHOOKSTRUCT pt As POINTAPI hwnd As Long wHitTestCode As Long dwExtraInfo As Long End Type Type RECT Left As Long Top As Long Right As Long Bottom As Long End Type Declare Function SetWindowsHookEx Lib "user32" Alias _ "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, _ ByVal hmod As Long, ByVal dwThreadId As Long) As Long Declare Function UnhookWindowsHookEx Lib "user32" _ (ByVal hHook As Long) As Long Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, _ ByVal nCode As Long, ByVal wParam As Long, lParam As Any) As Long Declare Sub CopyMemory Lib "KERNEL32" Alias "RtlMoveMemory" _ (lpvDest As Any, ByVal lpvSource As Long, ByVal cbCopy As Long) Declare Function ScreenToClient Lib "user32" (ByVal hwnd As Long, lpPoint As POINTAPI) As Long Public theForm As Form Public hHook As Long ' handle of Hook Procedure Public imgRect As RECT Sub EnableHook(ctl As Control) If hHook = 0 Then imgRect.Top = ctl.Top imgRect.Left = ctl.Left imgRect.Right = imgRect.Left + ctl.Width imgRect.Bottom = imgRect.Top + ctl.Height hHook = SetWindowsHookEx(WH_MOUSE, AddressOf MouseHookProc, App.hInstance, App.ThreadID) End If End Sub Sub FreeHook() Dim ret As Long If hHook <> 0 Then ret = UnhookWindowsHookEx(hHook) hHook = 0 End If End Sub Function MouseHookProc(ByVal code As Long, ByVal wParam As Long, _ ByVal lParam As Long) As Long Dim mStru As MOUSEHOOKSTRUCT, i As Long If wParam = WM_MOUSEMOVE Then CopyMemory mStru, lParam, LenB(mStru) 'mStru.pt的座标是萤幕座标,所以要经转换成相对於Form的座标 Call ScreenToClient(Screen.ActiveForm.hwnd, mStru.pt) '不在imgButton之内 If Not (mStru.pt.Y >= imgRect.Top And mStru.pt.Y <= imgRect.Bottom And _ mStru.pt.X >= imgRect.Left And mStru.pt.X <= imgRect.Right) Then MouseHookProc = 0 Call CallNextHookEx(hHook, code, wParam, lParam) Call FreeHook Debug.Print "Out of The Range " Exit Function Else Debug.Print "In The Range" End If End If MouseHookProc = 0 '表示要处理这个讯息 Call CallNextHookEx(hHook, code, wParam, lParam) End Function '以下在Form,需一个Command1 Private Sub Command1_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single) Call EnableHook(Command1) End Sub Private Sub Form_Load() Me.ScaleMode = 3 End Sub |