一些新定义:
热点:鼠标其实就是一个位图,但是从应用的角度看,他在用户区域里,其实指向唯一的一个像素,这个像素就是热点(hot spot)。
参数: 当鼠标移过窗口的显示区域时,窗口消息处理程序收到WM_MOUSEMOVE消息。当在窗口的显示区域中按下或者释放一个鼠标按键时,窗口消息处理程序会接收到下面这些消息:
键 | 按下 | 释放 | 按下(双键) |
左 | WM_LBUTTONDOWN | WM_LBUTTONUP | WM_LBUTTONDBLCLK |
中 | WM_MBUTTONDOWN | WM_MBUTTONUP | WM_MBUTTONDBLCLK |
右 | WM_RBUTTONDOWN | WM_RBUTTONUP | WM_RBUTTONDBLCLK |
对于所有这些消息来说,其lParam值均含有鼠标的位置:低字组为x坐标,高字组为y坐标,这两个坐标是相对于窗口显示区域左上角的位置。您可以用LOWORD和HIWORD宏来提取这些值:
x = LOWORD (lParam) ; y = HIWORD (lParam) ;
wParam的值指示鼠标按键以及Shift和Ctrl键的状态。您可以使用表头文件WINUSER.H中定义的位屏蔽来测试wParam。MK前缀代表「鼠标按键」。
MK_LBUTTON
按下左键
MK_MBUTTON
按下中键
MK_RBUTTON
按下右键
MK_SHIFT
按下Shift键
MK_CONTROL
按下Ctrl键
例如,如果收到了WM_LBUTTONDOWN消息,而且值
wparam & MK_SHIFT是TRUE(非0),您就知道当左键按下时也按下了Shift键。
刷新问题:当你的鼠标在用户区域中划动的时候,windows不会为每个像素生成一个WM_MOUSEMOVE消息,受到
WM_MOUSEMOVE消息的频率的大小是要看你鼠标的硬件指数以及你的消息处理函数处理消息的速度.
窗口的激活问题:当鼠标在不活动窗口中按下左键时,windows会先将这个窗口激活,然后再往他的消息处理函数队列中加入一个WM_LBUTTONDOWN消息.
所以,当一个窗口被接受到WM_LBUTTOMDOWN时就可以说明,这个窗口是活动窗口.然后一个窗口处理函数会接受到一个没有对应的WM_LBOTTONDOWN的WM_LBUTTONUP消息.
这种情况发生在,你按左键时在一个窗口,然后鼠标拖动到另一个窗口,然后释放左键.所以按键消息会有两个例外:
1.消息处理程序可以「拦截鼠标」并且连续地接收鼠标消息,即使此时鼠标在该窗口显示区域之外。您将在本章的后面学习如何拦截鼠标。
2.显示一个系统模态消息框或者系统模态对话框,那么其它程序就不能接收鼠标消息。当系统模态消息框或者对话框活动时,禁止切换到其它窗口或者程序。一个显示系统模态消息框的例子,是当您关闭Windows时。
双击事件:你的程序要响应双击时间必须包括CS_DBLCLKS标示符....
wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS ;
如果你的程序中不包括CS_DBLCLKS那么,你点击鼠标两次在很快的时间间隔内,你的消息处理函数会收到这样的消息:
WM_LBUTTONDOWN
WM_LBUTTONUP
WM_LBUTTONDOWN
WM_LBUTTONUP //在这种情况下你可以通过GetMessageTime(void)来得到得到消息的相对时间,从而实现双击事件
如果你的程序包括CS_DBLCLKS,当双击鼠标时就会收到:
WM_LBUTTONDOWN WM_LBUTTONUP WM_LBUTTONDBLCLK //windows将第2个WM_LBUTTONDOWN替换为WM_LBUTTONCLK WM_LBUTTONUP
非显示区域鼠标事件:非显示区域鼠标事件有以下几种:
Button | Pressed | Released | Pressed (Second Click) |
Left | WM_NCLBUTTONDOWN | WM_NCLBUTTONUP | WM_NCLBUTTONDBLCLK |
Middle | WM_NCMBUTTONDOWN | WM_NCMBUTTONUP | WM_NCMBUTTONDBLCLK |
Right | WM_NCRBUTTONDOWN | WM_NCRBUTTONUP | WM_NCRBUTTONDBLCLK |
注意一下,其实就是在显示区域的事件名称之前加了NC(NonClient).
非显示区域的鼠标事件的参数值和显示区域的有些不同.
wParam:指明移动或者按鼠标按键的非显示区域,一般是以HT开头的标示符.
lParam:鼠标的x,y坐标,同样低八位为x坐标,高八位为y坐标,但是这个是屏幕坐标,要将屏幕坐标转化为显示区域坐标可以调用:
ScreenToClient (hwnd, &pt); ClientToScreen (hwnd, &pt);Hit-Test消息:消息名字为WM_NCHITTEST.这个消息是优先于所有其他的鼠标对于非显示区域鼠标消息,在处理WM_NCHITTEST时,从DefWindowProc传回的值将成为鼠标消息中的wParam参数,这个值可以是任意非显示区域鼠标消息的wParam值再加上以下内容:
HTCLIENT HTNOWHERE HTTRANSPARENT HTERROR | 显示区域 不在窗口中 窗口由另一个窗口覆盖 使DefWindowProc产生警示用的哔声 |
如果你想在你的程序中拦截鼠标消息,就可以这样做:
case WM_NCHITTEST:
return (LRESULT)HTNOWHERE;
捕获鼠标:在有的应用程序中,需要对不在自己程序的显示区域之内的鼠标事件也做处理,那么就要用到捕获鼠标的技术,捕获鼠标可以用WIN32 API函数来实现:
SetCapture(
HWND hwnd //捕获鼠标的窗口句柄
);
返回值:如果函数成功的话,就返回前一个捕获鼠标的窗口句柄,如果没有那么一个窗口就返回NULL
鼠标滚动:从WINNT开始,MS支持鼠标的滚动,应用程序需要处理鼠标滚动消息时,就要截获wm-mouseweel消息
WM_MOUSEWHEEL
fwKeys = LOWORD(wParam); // key flags
zDelta = (short) HIWORD(wParam); // wheel rotation,正数就是向前滚动,这个数是WHEEL_DELTA(120)的倍数或约数
xPos = (short) LOWORD(lParam); // horizontal position of pointer(屏幕坐标)
yPos = (short) HIWORD(lParam); // vertical position of pointer(屏幕坐标)