欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  科技

第七章 鼠标(CHECKER1)

程序员文章站 2023-11-24 17:58:52
CHECKER1程序将客户区划分成25个矩形,构成一个5*5的数组。如果在其中一个矩形内单击鼠标,就用X形填充该矩形。再次单击,则X形消失。 1 /* 2 CHECKER1.C -- Mouse Hit-Test Demo Program No.1 3 (c) Charles Petzold, 19 ......

CHECKER1程序将客户区划分成25个矩形,构成一个5*5的数组。如果在其中一个矩形内单击鼠标,就用X形填充该矩形。再次单击,则X形消失。

第七章 鼠标(CHECKER1)
  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程序显示结果如图所示:

第七章 鼠标(CHECKER1)

所有25个矩形具有相同的宽度和高度,这些宽度和高度被保存在cxBlock、cyBlock中。无论何时改变客户区的大小,程序都将重新计算cxBlock、cyBlock。WM_LBUTTONDOWN处理逻辑利用鼠标的坐标来判断哪个矩形被单击,然后在fState数组中使用位运算符(按位异或^)计算那个矩形的新状态,最后强制使该矩形失效,从而产生WM_PAINT消息。

如果客户区的宽度和高度不能被5整除,客户区的左边或底部就会出现一个小长条区域,不被举行覆盖。在这片区域进行鼠标单击时,CHECKER1程序会调用MessageBeep函数进行响应。

当CHECKER1程序收到WM_PAINT消息时,它会重新绘制整个客户区,利用GDI中的Rectangle函数画出所有的矩形。若fState值为真,则CHECKER1程序调用函数MoveToEx和函数LineTo函数画出两条直线。