下面的代码来自于书中的源码。注释是我个人的理解。
#include<windows.h>
#define DIVISIONS 5
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);//首先是一个回调函数的声明
int WINAPI WinMain (HINSTANCE hInstance,//应用程序当前实例的句柄
HINSTANCE hPrevInstance,//应用程序先前的实例句柄
PSTR szCmdLine,//指向应用程序命令行的字符串的指针
int iCmdShow)//指明窗口如何显示
{
static TCHAR szAppName[]=TEXT("Checker1");
HWND hwnd;//当前实例的句柄
MSG msg;//消息
WNDCLASS wndclass;//类名
wndclass.style=CS_HREDRAW | CS_VREDRAW;//窗口的显示方式,此处为水平重画和竖直重画
wndclass.cbClsExtra=0;//窗口扩展,此处为0
wndclass.cbWndExtra=0;//窗口实例扩展,此处为0
wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);//窗口背景颜色的设置,此处设置为白色
wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);//鼠标的显示方式,此处设置为标准型
wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION);//窗口的显示方式,此处设置为应用程序型
wndclass.hInstance=hInstance;//窗口的实例句柄
wndclass.lpfnWndProc=WndProc;//窗口回调函数
wndclass.lpszClassName=szAppName;//窗口类名
wndclass.lpszMenuName=NULL;//窗口菜单,此处没菜单设为NULL
if(!RegisterClass(&wndclass))//注册窗口,若注册失败,产生如下的信息
{
MessageBox(NULL,TEXT("Program requires Windows NT!"),
szAppName,MB_ICONERROR);
return 0;
}
//创建窗口,如果函数成功,返回值为新窗口的句柄:如果函数失败,返回值为NULL。若想获得更多错误信息,请调用GetLastError函数。
hwnd=CreateWindow(szAppName,
TEXT("Checker1 Mouse Hit-Test Demo!"),//窗口的名字
WS_OVERLAPPEDWINDOW,//指定创建窗口的风格
CW_USEDEFAULT,//指定窗口的初始水平位置,如果该参数被设为CW_USEDEFAULT则系统为窗口选择缺省的左上角坐标并忽略Y参数。
CW_USEDEFAULT,//指定窗口的初始垂直位置
CW_USEDEFAULT,//以设备单元指明窗口的宽度。若是CW_USEDEFAULT,则系统为窗口选择一个缺省的宽度
CW_USEDEFAULT,//以设备单元指明窗口的高度。若被设为CW_USEDEFAULT,则系统忽略nHeight参数。
NULL,//指向被创建窗口的父窗口或所有者窗口的句柄,此处为NULL
NULL,//菜单句柄,或依据窗口风格指明一个子窗口标识,此处为NULL
hInstance,//与窗口相关联的模块实例的句柄。
NULL);//指向一个值的指针,该值传递给窗口WM_CREATE消息
ShowWindow(hwnd,iCmdShow);//显示窗口,hWnd:指窗口句柄。iCmdShow:指定窗口如何显示。
UpdateWindow(hwnd);//更新窗口,hWnd:指窗口句柄。
while(GetMessage(&msg,NULL,0,0))//消息循环
{
TranslateMessage(&msg);//该函数将虚拟键消息转换为字符消息
DispatchMessage(&msg);//该函数分发一个消息给窗口程序。
}
return msg.wParam;//wParam是消息携带的参数,可以是个值,也可以是个地址
}
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)//回调函数
{
static BOOL fState[DIVISIONS][DIVISIONS];//一个布尔型的二维数组
static int cxBlock,cyBlock;//一个小矩形的宽度和高度
HDC hdc;//句柄
int x,y;
PAINTSTRUCT ps;//包含窗口需要绘制的信息
RECT rect;//一个矩形的结构体
switch(message)
{
case WM_SIZE:
cxBlock=LOWORD(lParam)/DIVISIONS;//获取每一个矩形的宽度
cyBlock=HIWORD(lParam)/DIVISIONS;//获取每一个矩形的高度
return 0;
case WM_LBUTTONDOWN://鼠标左击
x=LOWORD(lParam)/cxBlock;//获取左击点的横坐标
y=HIWORD(lParam)/cyBlock;//获取左击点的纵坐标
if(x<DIVISIONS&&y<DIVISIONS)//判断左击点是否在窗口内
{
fState[x][y]^=1;
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);//MessageBeep函数用来播放一个波形声音
return 0;
case WM_PAINT://对窗口进行绘画
hdc=BeginPaint(hwnd,&ps);//获取句柄
for(x=0;x<cxBlock;x++)
{
for(y=0;y<cyBlock;y++)
{
Rectangle(hdc,x*cxBlock,y*cyBlock,(x+1)*cxBlock,(y+1)*cyBlock);
if(fState[x][y])//如果鼠标在该矩形内左击,则画出两条对角线
{
MoveToEx(hdc,x*cxBlock,y*cyBlock,NULL);
LineTo(hdc,(x+1)*cxBlock,(y+1)*cyBlock);
MoveToEx(hdc,(x+1)*cxBlock,y*cyBlock,NULL);
LineTo(hdc,x*cxBlock,(y+1)*cyBlock);
}
}
}
EndPaint(hwnd,&ps);//释放句柄
return 0;
case WM_DESTROY://关闭窗口
PostQuitMessage(0);//该函数向系统表明有个线程有终止请求。通常用来响应WM_DESTROY消息。
return 0;
}
return DefWindowProc(hwnd,message,wParam,lParam);//该函数调用缺省的窗口过程来为应用程序没有处理的任何窗口消息提供缺省的处理
}
上传个图片记录一下成果,加油继续!!!