CHECKER1程序将客户区划分成25个矩形,构成一个5*5的数组。如果在其中一个矩形内单击鼠标,就用X形填充该矩形。再次单击,则X形消失。
1 /*-------------------------------------------- 2 CHECKER1.C -- Mouse Hit-Test Demo Program No.1 3 (c) Charles Petzold, 1998 4 --------------------------------------------*/ 5 6 #include <Windows.h> 7 8 #define DIVISION 5 9 10 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); 11 12 int WINAPI WinMain( __in HINSTANCE hInstance 13 , __in_opt HINSTANCE hPrevInstance 14 , __in LPSTR lpCmdLine 15 , __in int nShowCmd ) 16 { 17 static TCHAR szAppName[] = TEXT("Checker1"); 18 HWND hwnd; 19 MSG msg; 20 WNDCLASS wndclass; 21 22 wndclass.style = CS_HREDRAW | CS_VREDRAW; 23 wndclass.lpfnWndProc = WndProc; 24 wndclass.cbClsExtra = 0; 25 wndclass.cbWndExtra = 0; 26 wndclass.hInstance = hInstance; 27 wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); 28 wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); 29 wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 30 wndclass.lpszMenuName = NULL; 31 wndclass.lpszClassName = szAppName; 32 33 if (!RegisterClass(&wndclass)) 34 { 35 MessageBox(NULL, TEXT("Program requires Windows NT!") 36 , szAppName, MB_ICONERROR); 37 return 0; 38 } 39 40 hwnd = CreateWindow(szAppName, TEXT("Checker1 Mouse Hit-Test Demo") 41 , WS_OVERLAPPEDWINDOW 42 , CW_USEDEFAULT, CW_USEDEFAULT 43 , CW_USEDEFAULT, CW_USEDEFAULT 44 , NULL, NULL, hInstance, NULL); 45 46 ShowWindow(hwnd, nShowCmd); 47 UpdateWindow(hwnd); 48 49 while (GetMessage(&msg, NULL, 0, 0)) 50 { 51 TranslateMessage(&msg); 52 DispatchMessage(&msg); 53 } 54 55 return msg.wParam; 56 } 57 58 LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 59 { 60 static BOOL fState[DIVISION][DIVISION]; 61 static int cxBlock, cyBlock; 62 HDC hdc; 63 int x, y; 64 PAINTSTRUCT ps; 65 RECT rect; 66 67 switch (message) 68 { 69 case WM_SIZE: 70 cxBlock = LOWORD(lParam) / DIVISION; 71 cyBlock = HIWORD(lParam) / DIVISION; 72 return 0; 73 74 case WM_LBUTTONDOWN: 75 x = LOWORD(lParam) / cxBlock; 76 y = HIWORD(lParam) / cyBlock; 77 78 if (x < DIVISION && y < DIVISION) 79 { 80 fState[x][y] ^= 1; 81 82 rect.left = x * cxBlock; 83 rect.top = y * cyBlock; 84 rect.right = (x + 1) * cxBlock; 85 rect.bottom = (y + 1) * cyBlock; 86 87 InvalidateRect(hwnd, &rect, FALSE); 88 } 89 else 90 MessageBeep(0); 91 return 0; 92 93 case WM_PAINT: 94 hdc = BeginPaint(hwnd, &ps); 95 96 for (x = 0; x < DIVISION; ++x) 97 for (y = 0; y < DIVISION; ++y) 98 { 99 Rectangle(hdc, x * cxBlock, y * cyBlock 100 , (x + 1) * cxBlock, (y + 1) * cyBlock); 101 102 if (fState[x][y]) 103 { 104 MoveToEx(hdc, x * cxBlock, y * cyBlock, NULL); 105 LineTo(hdc, (x + 1) * cxBlock, (y + 1) * cyBlock); 106 MoveToEx(hdc, x * cxBlock, (y + 1) * cyBlock, NULL); 107 LineTo(hdc, (x + 1) * cxBlock, y * cyBlock); 108 } 109 } 110 111 EndPaint(hwnd, &ps); 112 return 0; 113 114 case WM_DESTROY: 115 PostQuitMessage(0); 116 return 0; 117 } 118 119 return DefWindowProc(hwnd, message, wParam, lParam); 120 }
CHECKER1程序显示结果如图所示:
所有25个矩形具有相同的宽度和高度,这些宽度和高度被保存在cxBlock、cyBlock中。无论何时改变客户区的大小,程序都将重新计算cxBlock、cyBlock。WM_LBUTTONDOWN处理逻辑利用鼠标的坐标来判断哪个矩形被单击,然后在fState数组中使用位运算符(按位异或^)计算那个矩形的新状态,最后强制使该矩形失效,从而产生WM_PAINT消息。
如果客户区的宽度和高度不能被5整除,客户区的左边或底部就会出现一个小长条区域,不被举行覆盖。在这片区域进行鼠标单击时,CHECKER1程序会调用MessageBeep函数进行响应。
当CHECKER1程序收到WM_PAINT消息时,它会重新绘制整个客户区,利用GDI中的Rectangle函数画出所有的矩形。若fState值为真,则CHECKER1程序调用函数MoveToEx和函数LineTo函数画出两条直线。