学习Excel技术,关注微信公众号:
excelperfect
问题:前不久,有个网友给我提了个问题要我帮助解决。这个问题是,在某单元格中有一个数字,当鼠标滚轮向上滚动时该单元格中的数字以0.01的间隔增加,向下滚动时以0.01的间隔减少?
探讨
很显然,这需要使用Windows API来捕获鼠标事件。说实话,我对Windows API研究不深,于是上网查了一下,根据查找的一些资料整理了一段代码:
Public hHook As LongPtr #If VBA7 Then PublicDeclare PtrSafe Function SetWindowsHookEx Lib "user32" Alias"SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As LongPtr,ByVal hmod As LongPtr, ByVal dwThreadId As Long) As LongPtr PublicDeclare PtrSafe Function UnhookWindowsHookEx Lib "user32" (ByVal hhkAs LongPtr) As Long PublicDeclare PtrSafe Function CallNextHookEx Lib "user32" (ByVal hHook AsLongPtr, ByVal ncode As Long, ByVal wParam As LongPtr, lParam As Any) AsLongPtr PublicDeclare PtrSafe Function GetCurrentThreadId Lib "kernel32" () As Long#End If Public Const WH_MOUSE = 7Public Const WM_RBUTTONDOWN = &H204Public Const WM_MOUSEWHEEL = &H20A Sub BeginHK() '获取当前的线程ID i =GetCurrentThreadId '这里安装的是键盘钩子 hHook =SetWindowsHookEx(WH_MOUSE, AddressOf HookProc, 0, i)End Sub 'Hook程序Public Function HookProc(ByVal code As Long, ByValwParam As Long, ByVal lParam As Long) As LongPtr Dimwks As Worksheet Set wks =Excel.ActiveSheet '如果code参数<0,则一定要返回CallNextHookEx函数的返回值 If code< 0 Then HookProc = CallNextHookEx(hHook, code, wParam, lParam) Else SelectCase wParam '按下鼠标右键,则退出 Case WM_RBUTTONDOWN EndHK '使用鼠标滚轮 Case WM_MOUSEWHEEL wks.Range("B2").Value = wks.Range("B2").Value + 0.01 EndSelect '如果要拦截处理消息,则HookProc函数的返回值一定要是非0,不然会陷入死循环 HookProc = 1 End IfEnd Function Sub EndHK() UnhookWindowsHookEx hHookEnd Sub
但是,这段代码只能实现单元格中的数值随着滑动鼠标滚轮不断增加0.01,无论向前滚动还是向后滚动,如下图1所示。(注:可按鼠标右键退出程序)
图1
我想要的是,当鼠标滚轮向前滚动时,单元格中的数值增加0.01,向后滚动时,减少0.01。
于是,继续上网搜索资料,终于查到一段:
我们知道VB应用程序响应的Windows传来的消息,需要通过VB解释。可是很不幸,虽然VB解释所有的消息,却只让用户程序在事件中处理部分消息,VB自己处理其他的消息,或者忽略这些消息。
在VB5.0以前应用程序无法越过VB直接处理消息,微软从VB5.0开始提供AddressOf 运算符,该运算符可以让用户程序将函数或者过程的地址传递给一个API函数。这样我们就可以在VB应用程序中编写自己的窗口处理函数,通过AddressOf 运算符将在VB中定义的窗口地址传递给窗口处理函数,从而绕过VB的解释器,自己处理消息。事实上,该方法可用于在VB中处理任何消息。
实现应用程序支持鼠标滚轮的关键是,捕获鼠标滚轮的消息 MSH_MOUSEWHEEL、WM_MOUSEWHEEL。其中MSH_MOUSEWHEEL是为95准备的,需要Intellimouse驱动程序,而WM_MOUSEWHEEL是目前各版本Windows(98/NT40/2000)内置的消息。下面是WM_MOUSEWHEEL的语法。
WM_MOUSEWHEEL
fwKeys = LOWORD(wParam); /* key flags */
zDelta = (short) HIWORD(wParam);
/* wheel rotation */
xPos = (short) LOWORD(lParam);
/* horizontal position of pointer */
yPos = (short) HIWORD(lParam);
/* vertical position of pointer */
其中:fwKeys指出是否有CTRL、SHIFT、鼠标键(左、中、右、附加)按下,允许复合。zDelta传递滚轮滚动的快慢,该值小于零表示滚轮向后滚动(朝用户方向),大于零表示滚轮向前滚动(朝显示器方向)。lParam指出鼠标指针相对屏幕左上的x、y轴坐标。
滚轮按钮相当于普通的三键鼠标的中键,根据滚轮按钮的动作,Windows分别发出WM_MBUTTONUP、WM_MBUTTONDOWN、WM_MBUTTONDBLCLK消息,这些消息VB已经在鼠标事件中支持。
但是,当我使用HIWORD(wParam)时,程序却崩溃了!有没有哪位朋友在这方面有研究的,可否指教一下:如何捕捉鼠标滚轮的向前或向后滚动?