第七章 鼠标(CHECKER1)

时间:2023-02-01 22:42:55

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

 /*--------------------------------------------
CHECKER1.C -- Mouse Hit-Test Demo Program No.1
(c) Charles Petzold, 1998
--------------------------------------------*/ #include <Windows.h> #define DIVISION 5 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain( __in HINSTANCE hInstance
, __in_opt HINSTANCE hPrevInstance
, __in LPSTR lpCmdLine
, __in int nShowCmd )
{
static TCHAR szAppName[] = TEXT("Checker1");
HWND hwnd;
MSG msg;
WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = ;
wndclass.cbWndExtra = ;
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 ;
} hwnd = CreateWindow(szAppName, TEXT("Checker1 Mouse Hit-Test Demo")
, WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT, CW_USEDEFAULT
, CW_USEDEFAULT, CW_USEDEFAULT
, NULL, NULL, hInstance, NULL); ShowWindow(hwnd, nShowCmd);
UpdateWindow(hwnd); while (GetMessage(&msg, NULL, , ))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
} return msg.wParam;
} LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static BOOL fState[DIVISION][DIVISION];
static int cxBlock, cyBlock;
HDC hdc;
int x, y;
PAINTSTRUCT ps;
RECT rect; switch (message)
{
case WM_SIZE:
cxBlock = LOWORD(lParam) / DIVISION;
cyBlock = HIWORD(lParam) / DIVISION;
return ; case WM_LBUTTONDOWN:
x = LOWORD(lParam) / cxBlock;
y = HIWORD(lParam) / cyBlock; if (x < DIVISION && y < DIVISION)
{
fState[x][y] ^= ; rect.left = x * cxBlock;
rect.top = y * cyBlock;
rect.right = (x + ) * cxBlock;
rect.bottom = (y + ) * cyBlock; InvalidateRect(hwnd, &rect, FALSE);
}
else
MessageBeep();
return ; case WM_PAINT:
hdc = BeginPaint(hwnd, &ps); for (x = ; x < DIVISION; ++x)
for (y = ; y < DIVISION; ++y)
{
Rectangle(hdc, x * cxBlock, y * cyBlock
, (x + ) * cxBlock, (y + ) * cyBlock); if (fState[x][y])
{
MoveToEx(hdc, x * cxBlock, y * cyBlock, NULL);
LineTo(hdc, (x + ) * cxBlock, (y + ) * cyBlock);
MoveToEx(hdc, x * cxBlock, (y + ) * cyBlock, NULL);
LineTo(hdc, (x + ) * cxBlock, y * cyBlock);
}
} EndPaint(hwnd, &ps);
return ; case WM_DESTROY:
PostQuitMessage();
return ;
} return DefWindowProc(hwnd, message, wParam, lParam);
}

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函数画出两条直线。