1. 程式人生 > >第七章 鼠標(CHECKER1)

第七章 鼠標(CHECKER1)

技術 uname rect amp tom line lineto bject lock

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.C

CHECKER1程序顯示結果如圖所示:

技術分享圖片

所有25個矩形具有相同的寬度和高度,這些寬度和高度被保存在cxBlock、cyBlock中。無論何時改變客戶區的大小,程序都將重新計算cxBlock、cyBlock。WM_LBUTTONDOWN處理邏輯利用鼠標的坐標來判斷哪個矩形被單擊,然後在fState數組中使用位運算符(按位異或^)計算那個矩形的新狀態,最後強制使該矩形失效,從而產生WM_PAINT消息。

如果客戶區的寬度和高度不能被5整除,客戶區的左邊或底部就會出現一個小長條區域,不被舉行覆蓋。在這片區域進行鼠標單擊時,CHECKER1程序會調用MessageBeep函數進行響應。

當CHECKER1程序收到WM_PAINT消息時,它會重新繪制整個客戶區,利用GDI中的Rectangle函數畫出所有的矩形。若fState值為真,則CHECKER1程序調用函數MoveToEx和函數LineTo函數畫出兩條直線。

第七章 鼠標(CHECKER1)