API/COM/系统相关
Access或VB为任何控件添加鼠标滚轮事件(适用VB及VBA)
2017-01-20 15:02:33

Access或VB为任何控件添加鼠标滚轮事件

Access及VB 的有些控件不支持鼠标滚轮,或滚轮的行为不是你需要的,默认的滚轮可能是上下移动,本程序实现捕获任何控件的鼠标滚轮事件。

程序运行后,当窗口的焦点控件是水平滚动条时,滚动鼠标滚轮,滚动条的滑块即可上下移动。

当窗口焦点控件是按钮时,滚动鼠标滚轮,可改变窗口的大小。

单击一下图片框,滚动鼠标滚轮可改变图片框的大小。

滚动鼠标滚轮要实现的效果,可通过修改模块的“MousScroll”过程实现。

调试注意:本程序是通过拦截窗口消息捕获鼠标滚轮事件的。VB 在处理窗口消息回调函数的时候,运行时如果设置断点,很容易造成程序无响应异常终止。因此,修改代码后应及时保存。

如果是Access, 可以在控件的获得焦点事件(GetFocus)绑定钩子,在失去焦点事件(LostFocus)中释放钩子

以下代码摘自网络:

'''本程序包含一个窗体 Form1 和一个模块 Module1,在 VB6 和 WinXP 下调试通过。

'以下是窗体 Form1 代码 =====================================

'在窗体添加以下控件,不用设置任何属性:

'   按钮1个:Command1

'   图片框1个:Picture1

'   水平滚动条1个:HScroll1

'   垂直滚动条1个:VScroll1

 

Private Sub Form_Load()

   Me.Caption = "捕获鼠标滚轮事件"

   Command1.Caption = "新窗口"

   VScroll1.Max = 100

   HScroll1.Max = 100

   Picture1.Picture = Me.Icon

End Sub

Private Sub Form_Activate()

   StartProc Me '开始拦截窗口消息

End Sub

Private Sub Form_Unload(Cancel As Integer)

   StopProc '停止拦截窗口消息

End Sub

Private Sub Command1_Click()

  Dim nForm As New Form1

  nForm.Show

End Sub

以下是模块 Module1 代码 =====================================

Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long

Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long

Private Const GWL_WNDPROC = -4

Private Const WM_MOUSEWHEEL = &H20A

Dim moProc As Long, moForm As Form

'自定滚轮事件

Private Sub MousScroll(ByVal nVal As Single)

   '获取鼠标滚轮事件后,要做的事情

   'nVal=1 表示鼠标滚轮向下滚,nVal=-1 表示鼠标滚轮向上滚

   Dim Kj As Object, nType As String, W As Single, H As Single

   

   If moForm Is Nothing Then Exit Sub

   On Error Resume Next

   Set Kj = moForm.ActiveControl

   nType = TypeName(Kj)

   

   Select Case nType

   Case "HScrollBar", "VScrollBar" '焦点控件是滚动条

      nVal = Kj.Value + nVal * 3

      If nVal > Kj.Max Then nVal = Kj.Max

      If nVal < Kj.Min Then nVal = Kj.Min

      Kj.Value = nVal

   Case "PictureBox" '焦点控件是图片框,改变控件大小,每次 3 个像素

      W = Kj.Container.ScaleX(Kj.Width, Kj.Container.ScaleMode, 3) + nVal * 3

      H = Kj.Container.ScaleY(Kj.Height, Kj.Container.ScaleMode, 3) + nVal * 3

      If W < 4 Or H < 4 Then Exit Sub

      W = Kj.Container.ScaleX(W, 3, Kj.Container.ScaleMode)

      H = Kj.Container.ScaleY(H, 3, Kj.Container.ScaleMode)

      Kj.Move Kj.Left, Kj.Top, W, H

   Case Else '其他情况:改变窗体大小,每次 3 个像素

      W = moForm.Width + nVal * Screen.TwipsPerPixelX * 3

      H = moForm.Height + nVal * Screen.TwipsPerPixelY * 3

      If W < 90 Or H < 90 Then Exit Sub

      moForm.Move moForm.Left, moForm.Top, W, H

   End Select

End Sub

Private Function WinProc(ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

   '窗口消息回调函数

   If wMsg = WM_MOUSEWHEEL Then

      If wParam = -7864320 Then MousScroll 1 '鼠标滚轮向下滚

      If wParam = 7864320 Then MousScroll -1 '鼠标滚轮向上滚

   End If

   WinProc = CallWindowProc(moProc, hWnd, wMsg, wParam, lParam)

End Function

Public Sub StartProc(nForm As Form)

   '开始拦截窗口消息

   Dim nWnd As Long

   On Error GoTo Err1

   nWnd = nForm.hWnd

   Call StopProc '开始前,先还原

   On Error GoTo 0

   moProc = GetWindowLong(nWnd, GWL_WNDPROC)

   SetWindowLong nWnd, GWL_WNDPROC, AddressOf WinProc

   Set moForm = nForm

   Exit Sub

Err1:

   MsgBox Err.Description

End Sub

Public Sub StopProc()

   '停止拦截窗口消息:还原窗口消息地址

   If moProc = 0 Or (moForm Is Nothing) Then Exit Sub

   SetWindowLong moForm.hWnd, GWL_WNDPROC, moProc

   moProc = 0

End Sub

其它相关可参考的代码:

VB 获得鼠标滚轮的事件

  '窗体代码Private Sub Form_Load()HookMouse Me.hwndEnd SubPrivate Sub Form_Unload(Cancel As Integer)UnHookMouse Me.hwndEnd Sub

  '模块代码'***********************************************************'mMouseWheel'鼠标滚轮的事件检测'***********************************************************Option ExplicitPrivate Declare Function CallWindowProc Lib "User32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As LongPrivate Declare Function SetWindowLong Lib "User32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As LongPrivate Const GWL_WNDPROC = -4Private Const WM_MOUSEWHEEL = &H20AGlobal lpPrevWndProcA As LongPublic bMouseFlag As Boolean '鼠标事件激活标志Public Sub HookMouse(ByVal hwnd As Long)lpPrevWndProcA = SetWindowLong(hwnd, GWL_WNDPROC, AddressOf WindowProc)End SubPublic Sub UnHookMouse(ByVal hwnd As Long)SetWindowLong hwnd, GWL_WNDPROC, lpPrevWndProcAEnd SubPrivate Function WindowProc(ByVal hw As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As LongSelect Case uMsgCase WM_MOUSEWHEEL '滚动Dim wzDelta, wKeys As Integer'wzDelta传递滚轮滚动的快慢,该值小于零表示滚轮向后滚动(朝用户方向),'大于零表示滚轮向前滚动(朝显示器方向)wzDelta = HIWORD(wParam)'wKeys指出是否有CTRL=8、SHIFT=4、鼠标键(左=2、中=16、右=2、附加)按下,允许复合wKeys = LOWORD(wParam)'--------------------------------------------------If wzDelta < 0 Then '朝用户方向Form1.ClsForm1.Print "朝用户方向滚"Else '朝显示器方向Form1.ClsForm1.Print "朝显示器方向"End If'--------------------------------------------------Case ElseWindowProc = CallWindowProc(lpPrevWndProcA, hw, uMsg, wParam, lParam)End SelectEnd FunctionPrivate Function HIWORD(LongIn As Long) As IntegerHIWORD = (LongIn And &HFFFF0000) \ &H10000 '取出32位值的高16位End FunctionPrivate Function LOWORD(LongIn As Long) As IntegerLOWORD = LongIn And &HFFFF& '取出32位值的低16位End Function