这篇我们主要看两个消息处理程序:wndproc和about
WndProc
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
首先我们来回顾下函数头,LRESULT是一个long类型的指针,CALLBACK表示这是个回调函数,HWND是窗口句柄,WPARAM和LPARAM都是32位无符号整型代表附加消息。该函数作用用于主窗口的消息处理。
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// 分析菜单选择:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: 在此处添加使用 hdc 的任何绘图代码...
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
在分析这段代码前我们要对常用的消息名称有所了解
WM_CREATE
应用程序创建一个窗口
WM_DESTROY
一个窗口被销毁
WM_MOVE
移动一个窗口
WM_SIZE
改变一个窗口的大小
WM_PAINT
要求一个窗口重画自己
WM_KEYDOWN
按下一个键
WM_KEYUP
释放一个键
WM_MOUSEMOVE
移动鼠标
WM_LBUTTONDOWN
按下鼠标左键
WM_LBUTTONUP
释放鼠标左键
WM_COMMAND
当用户从菜单中选择命令项时、控件向其父窗口发送通知消息或转换快捷键时发送。
WM_INITDIALOG
在显示对话框之前立即发送到对话框过程。对话框过程通常使用此消息初始化控件并执行影响对话框外观的任何其他初始化任务。
简单来说就是在对话框要创建了但还没显示出来前发出的消息。
然后我们来分析代码
函数一开始对进来的消息进行分支的判断,如果消息是用户从菜单中选择了命令项即WM_COMMAND,那么我们要看用户选的是哪个选项,可是就算我们知道了哪个选项,我们怎么拿这个选项来做事情呢,我们自己要知道每个命令项的ID才能做case的判断,而其实每个命令项的ID我们都可以在资源视图中找到且能直观地看到。
首先我们在VS左视图的资源管理器里下面找到资源视图并切换
点击Menu然后双击IDE_HELLOWINDOWS
右键点击菜单里的退出按钮,可以看到
点击属性,我们就可以看到该按钮对应的ID号了
同时,这个Menu是可以编辑的。在设置对应ID后还可以在Resource.h里设置对应的数字编号。
OK,刚才我们讲到需要得到用户单击的那个命令项的ID,那么我们该怎么获取呢?很简单,传进来的WParam的低位里附带了命令项ID信息,所以我们只要获取WParam的低位就行了。int wmId = LOWORD(wParam);wmld就是获取到的ID。然后找到对应的命令项ID匹配,然后你就可以在case后面写你单击该命令项后想做的事情了。
然后我们看case里的内容,IDM_ABOUT就是那个“帮助”下的“关于”按钮,按下后会创建一个对话框:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
对话框的创建可查看MSDN里的介绍,在此不多赘述
https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-dialogboxa
然后我们直接看default后面的内容:return DefWindowProc(hWnd, message, wParam, lParam);
这个函数主要用于接收消息并不做出任何响应,换句话说就是进到这里的消息都会被无视。
然后我们看WM_PAINT的情况:
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: 在此处添加使用 hdc 的任何绘图代码...
}
break;
需要知道的是WM_PAINT在窗口第一次显示时,大小改变时,移动时,以及调用某些函数如Invalidate()时会触发该消息。
最简单的,我们可以在TODO下写这样一段代码:
HBRUSH hbrush = CreateSolidBrush(0x000fff);
RECT r = { 100,100,200,200 };
FillRect(hdc, &r, hbrush);
就可以绘制最简单的矩形了。
最后WM_DESTROY的情况:
case WM_DESTROY:
PostQuitMessage(0);
break;
就是给消息队列塞进一条WM_QUIT的消息。
最后我们来快速地看一下About消息处理程序
大概看一遍你会发现很多讲过了,所以我只讲下WM_COMMAND里面的情况。
在此多啰嗦一句,WM_COMMAND消息是只要是用户单击了控件就触发,不一定非要菜单命令项才行(也许不一定是所有控件都触发,但对于我们新手来说暂时可以这么理解),而结合我们之前的操作也可以理解win32的编程模式还是有点保留了可视化的效果,在资源管理器中编辑对话框,在对话框中编辑控件,给对话框设置窗口过程处理,而在这个过程处理中我们可以根据它点击了哪个控件(通过ID)来做一些相应的操作。
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
EndDialog结束对话框。。所以没啥好讲的,就这样吧,有什么理解不到位的后续补充。