WM_LBUTTONDOWN、WM_LBUTTONUP、WM_MOUSEMOVE是鼠标的三个基本消息处理,分别表示鼠标左键按下、鼠标左键松开、鼠标移动,这三个主消息的副消息的内容完全相同,下面小雅用WM_MOUSEMOVE的二个副消息为例,来剖析其内容究竟是什么。
lParam副消息存放的是鼠标的座标位置,字节的低4位为x座标,高4位为y座标。用位操作符&很容易就取到鼠标的x和y座标,VC也提供了宏HIWORD()和LOWORD()。
wParam的高4位不用,低4位表示组合键的使用状态。第1位为“1”表示鼠标左键按下,第2位为“1”表示鼠标右键按下,第3位为“1”表示Shift键按下,第4位为“1”表示Ctrl键按下,这4种状态可以组合使用。例如,鼠标左右键同时按下,wParam为3;鼠标左右键和Shift、Ctrl键全部按下则wParam为F。
例子:
case WM_LBUTTONDOWN:
if (LOWORD(wParam) & 0x01)
{
MessageBox(hWnd, "left mouse", NULL, MB_OK);
}
break;
光标:
作图时,习惯上按下鼠标左键时光标变为“十字形”,松开后恢复为缺省的“箭头”,因此在WM_LBUTTONDOWN消息处理和WM_LBUTTONUP消息处理中要增加对鼠标光标的控制。
光标都是由窗口类最初设定的,一般为箭头,但有人会改变成自己喜好的光标。窗口要控制光标首先要取当前光标的类型并保存,然后取消窗口对光标的控制,并设置光标为“十字形”,这些都是在WM_LBUTTONDOWN的消息处理程序中实现的。在WM_LBUTTONUP的消息处理程序中,还必须恢复窗口对光标的控制,并立即让光标成为窗口默认的光标。
设置光标是用SetCursor()函数,因其简单,不作解释应该没有问题。取当前系统光标的类型是用GetClassLong()函数,设置系统光标的类型是用SetClassLong()函数,这2个函数很重要,并不仅仅针对光标,根据参数的不同,可以取得或设置窗口类型、背景、图标、光标、菜单等等,这些全是注册窗口类时设置的内容。
如:
HCURSOR clsCur;
case WM_LBUTTONDOWN:
clsCur = (HCURSOR)GetClassLong(hWnd,GCL_HCURSOR); //取当前的光标值 并保存
SetClassLong(hWnd,GCL_HCURSOR,NULL); //关闭窗口类对光标的控制
SetCursor (LoadCursor(NULL, IDC_CROSS)); //设置光标为十字形
break;
case WM_LBUTTONUP:
SetClassLong(hWnd,GCL_HCURSOR,(LONG) clsCur); //恢复窗口类对光标的控制
SetCursor (LoadCursor(NULL, IDC_ARROW)); //恢复箭头光标
break;
画线:
HCURSOR clsCur;
POINTS point;
case WM_LBUTTONDOWN:
clsCur = (HCURSOR)GetClassLong(hWnd,GCL_HCURSOR); //取当前的光标值
SetClassLong(hWnd,GCL_HCURSOR,NULL); //关闭窗口类对光标的控制
SetCursor (LoadCursor(NULL, IDC_CROSS)); //设置光标为十字形
point .x = LOWORD(lParam);
point .y = HIWORD(lParam);
break;
case WM_LBUTTONUP:
SetCursor (LoadCursor(NULL, IDC_ARROW));
hdc = GetDC(hWnd);
MoveToEx(hdc, point.x, point.y, NULL);
LineTo(hdc, LOWORD(lParam), HIWORD(lParam));
ReleaseDC(hWnd, hdc);
break;
一个不错的例子:
HCURSOR clsCur;
POINTS start;
bool bDrawing;
case WM_LBUTTONDOWN:
bDrawing = true; //描画状态开始
start = MAKEPOINTS(lParam); //开始点保存于start中
//取得窗口有效区
RECT rect;
GetClientRect(hWnd,&rect);
//转换窗口有效区为屏幕座标
POINT point;
point.x = 0, point.y = 0;
ClientToScreen(hWnd,&point);
rect.top = point.y;
rect.left = point.x;
rect.bottom += rect.top;
rect.right += rect.left;
//将光标限定在窗口有效区内
ClipCursor(&rect); //rect一定要是屏幕座标
if (!clsCur)
{
clsCur = (HCURSOR)GetClassLong(hWnd,GCL_HCURSOR); // 取当前窗口的光标
}
SetClassLong(hWnd,GCL_HCURSOR,NULL); //设置当前窗口的光标为NULL
SetCursor(LoadCursor(NULL, IDC_CROSS)); //设置当前光标为十字形
break;
case WM_MOUSEMOVE:
HDC hdc;
hdc = GetDC(hWnd);
if (bDrawing) {
MoveToEx(hdc, start.x, start.y,NULL);
LineTo(hdc, LOWORD(lParam), HIWORD(lParam));
}
ReleaseDC(hWnd, hdc);
break;
case WM_LBUTTONUP:
bDrawing = false; //描画状态结束
ClipCursor(NULL); //使光标可以在屏幕任意位置移动
SetClassLong(hWnd,GCL_HCURSOR, (long)clsCur); //设置窗口光标为原先的光标
SetCursor((HCURSOR)clsCur); //设置当前光标为原先的光标
break;