Windows的GetKeyState函数能够返回鼠标按钮或Shift等键的状态,当GetKeyState函数返回一个负值时,表示已经按下了鼠标按钮或相应的Shift或Ctrl键。
在没有按下鼠标时,不能使用GetKeyState函数。
在鼠标事件的时候,有时候,需要对参数wParam和MK_XX进行位与运算
if(wParam & MK_SHIFT) { if(wParam & MK_CONTROL) { 按下Shift+Ctrl } else{ 按下Shift键 } } else { if(wParam & MK_CONTROL) { 按下Ctrl键 } else { Shift和Ctrl键都没有按下 } }
又如:
case WM_LBUTTONDOWN: if(!(wParam & MK_SHIFT)) { 这里处理左键; } return 0;
下面常用的虚拟键代码:
VK_LBUTTON VK_RBUTTON VK_MBUTTON VK_SHIFT VK_CONTROL VK_LMENU VK_RMENU
看看非客户区鼠标消息
窗口的非客户区包括标题栏,菜单和窗口滚动条。
鼠标按钮产生的消息如下所示:
按钮 | 按下 | 释放 | 第二次按下按钮 |
左键 | WM_NCLBUTTONDOWN | WM_NCLBUTTONUP | WM_NCLBUTTONDBLCLK |
中键 | WM_NCMBUTTONDOWN | WM_NCMBUTTONUP | WM_NCMBUTTONDBLCLK |
右键 | WN_NCRBUTTONDOWN | WM_NCRBUTTONUP | WM_NCRBUTTONDBLCLK |
利用下面两个函数,可以将屏幕坐标和客户区坐标进行互换
ScreenToClient(hwnd,&pt); ClientToScreen(hwnd,&pt);
击中测试消息:
HTCLIENT | 客户区 |
HTNOWHERE | 不在任何窗口 |
HTTRANSPARENT | 被另一个窗口覆盖的窗口 |
HTERROR | 使函数DefWindowProc产生一个警示声 |
下面这个代码,可以让你的窗口叫天天不应,叫地地不灵
case WM_NCHITTEST: return (LRESULT)HTNOWHERE;
此时,无论鼠标位于窗口任何位置,包括系统菜单图标,调整大小和关闭按钮,鼠标按钮操作都将失效。
一个简单的程序,该程序将客户区划分成25个矩形,构成5X5的数组,如果在其中一个矩形内单击鼠标,就用X形填充该矩形,再次单击,则X形消失;
#include<windows.h> #include<windowsx.h> #define DIVISIONS 5 LRESULT CALLBACK WindowProc( HWND hwnd, // handle to window UINT uMsg, // message identifier WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ); int WINAPI WinMain( HINSTANCE hInstance, // handle to current instance HINSTANCE hPrevInstance, // handle to previous instance LPSTR lpCmdLine, // command line int nCmdShow // show state ) { static TCHAR szAppName[]=TEXT("leidemingzi"); HWND hwnd; MSG msg; WNDCLASS wndclass; wndclass.cbClsExtra=0; wndclass.cbWndExtra=0; wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.hCursor=LoadCursor(NULL,IDC_ARROW); wndclass.hIcon=LoadIcon(NULL,IDI_ERROR); wndclass.hInstance=hInstance; wndclass.lpfnWndProc=WindowProc; wndclass.lpszClassName=szAppName; wndclass.lpszMenuName=NULL; wndclass.style=CS_HREDRAW|CS_VREDRAW; if(!RegisterClass(&wndclass)){ MessageBox(NULL,TEXT("the program require window NT"),szAppName,MB_ICONERROR); return 0; } hwnd=CreateWindow( szAppName, // registered class name TEXT("this is title"), // window name WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // horizontal position of window CW_USEDEFAULT, // vertical position of window CW_USEDEFAULT, // window width CW_USEDEFAULT, // window height NULL, // handle to parent or owner window NULL, // menu handle or child identifier hInstance, // handle to application instance NULL // window-creation data ); ShowWindow(hwnd,nCmdShow); UpdateWindow(hwnd); while(GetMessage(&msg,NULL,0,0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK WindowProc( HWND hwnd, // handle to window UINT uMsg, // message identifier WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ) { HDC hdc; PAINTSTRUCT ps; static BOOL fState[DIVISIONS][DIVISIONS]; static int cxBlock,cyBlock; int x,y; RECT rect; switch(uMsg) { case WM_SIZE: cxBlock=LOWORD(lParam)/DIVISIONS;//横竖都分成五份 cyBlock=HIWORD(lParam)/DIVISIONS; return 0; case WM_LBUTTONDOWN: x=GET_X_LPARAM(lParam)/cxBlock; y=GET_Y_LPARAM(lParam)/cyBlock; if(x<DIVISIONS && y<DIVISIONS) { fState[x][y]^=1;//异或,如果已经显示了X,再点击,则X消失,如果没有X显示,则点击会显示X rect.left=x*cxBlock; //标记该被点击的矩形区域,为后面“显示”和“消失”固定一个范围 rect.top=y*cyBlock; rect.right=(x+1)*cxBlock; rect.bottom=(y+1)*cyBlock; InvalidateRect(hwnd,&rect,FALSE); }else{ MessageBeep(0); } return 0; case WM_PAINT: hdc=BeginPaint(hwnd,&ps); for(x=0;x<DIVISIONS;++x) { for(y=0;y<DIVISIONS;++y) { Rectangle(hdc,x*cxBlock,y*cyBlock,(x+1)*cxBlock,(y+1)*cyBlock); if(fState[x][y])//画“X” { MoveToEx(hdc,x*cxBlock,y*cyBlock,NULL); LineTo(hdc,(x+1)*cxBlock,(y+1)*cyBlock); MoveToEx(hdc,x*cxBlock,(y+1)*cyBlock,NULL); LineTo(hdc,(x+1)*cxBlock,y*cyBlock); } } } EndPaint(hwnd,&ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd,uMsg,wParam,lParam); }
运行结果如下:
可以用子窗口完成相同的功能:
#include <windows.h> #define DIVISIONS 5 LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; LRESULT CALLBACK ChildWndProc (HWND, UINT, WPARAM, LPARAM) ; TCHAR szChildClass[] = TEXT ("Checker3_Child") ; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT ("Checker3") ; HWND hwnd ; MSG msg ; WNDCLASS wndclass ; wndclass.style = CS_HREDRAW | CS_VREDRAW ; wndclass.lpfnWndProc = WndProc ; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ; wndclass.lpszMenuName = NULL ; wndclass.lpszClassName = szAppName ; if (!RegisterClass (&wndclass)) { MessageBox (NULL, TEXT ("Program requires Windows NT!"), szAppName, MB_ICONERROR) ; return 0 ; } wndclass.lpfnWndProc = ChildWndProc ; wndclass.cbWndExtra = sizeof (long) ; wndclass.hIcon = NULL ; wndclass.lpszClassName = szChildClass ; RegisterClass (&wndclass) ; hwnd = CreateWindow (szAppName, TEXT ("Checker3 Mouse Hit-Test Demo"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL) ; ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ; while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } return msg.wParam ; } LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static HWND hwndChild[DIVISIONS][DIVISIONS] ; int cxBlock, cyBlock, x, y ; switch (message) { case WM_CREATE : for (x = 0 ; x < DIVISIONS ; x++) for (y = 0 ; y < DIVISIONS ; y++) hwndChild[x][y] = CreateWindow (szChildClass, NULL, WS_CHILDWINDOW | WS_VISIBLE, 0, 0, 0, 0, hwnd, (HMENU) (y << 8 | x), (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE), NULL) ; return 0 ; case WM_SIZE : cxBlock = LOWORD (lParam) / DIVISIONS ; cyBlock = HIWORD (lParam) / DIVISIONS ; for (x = 0 ; x < DIVISIONS ; x++) for (y = 0 ; y < DIVISIONS ; y++) MoveWindow (hwndChild[x][y], x * cxBlock, y * cyBlock, cxBlock, cyBlock, TRUE) ; return 0 ; case WM_LBUTTONDOWN : MessageBeep (0) ; return 0 ; case WM_DESTROY : PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, message, wParam, lParam) ; } LRESULT CALLBACK ChildWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc ; PAINTSTRUCT ps ; RECT rect ; switch (message) { case WM_CREATE : SetWindowLong (hwnd, 0, 0) ; // on/off flag return 0 ; case WM_LBUTTONDOWN : SetWindowLong (hwnd, 0, 1 ^ GetWindowLong (hwnd, 0)) ; InvalidateRect (hwnd, NULL, FALSE) ; return 0 ; case WM_PAINT : hdc = BeginPaint (hwnd, &ps) ; GetClientRect (hwnd, &rect) ; Rectangle (hdc, 0, 0, rect.right, rect.bottom) ; if (GetWindowLong (hwnd, 0)) { MoveToEx (hdc, 0, 0, NULL) ; LineTo (hdc, rect.right, rect.bottom) ; MoveToEx (hdc, 0, rect.bottom, NULL) ; LineTo (hdc, rect.right, 0) ; } EndPaint (hwnd, &ps) ; return 0 ; } return DefWindowProc (hwnd, message, wParam, lParam) ; }