6.vc从零开始 -- Win32项目hello world(四)

WndProc

这个是用户定义的窗口消息处理函数,这个函数是在MyRegisterClass中的RegisterClassEx函数用到的。定义要符合格式:
LRESULT CALLBACK WindowProc(HWND hwnd , UINT uMsg , WPARAM wParam , LPARAM lParam);
LRESULT是返回值类型,本质上是long类型;
CALLBACK是函数协议类型,本质上是__stdcall
参数第一个是窗口句柄,基本上只能是这个消息处理函数对应的窗口的句柄;
第二个参数是消息类型,一个无符号整数的数值,对应windows定义的各种消息;
第三个和第四个是消息附带的参数,未必两个都用,甚至可能某些消息没有参数则两个参数都是0。WPARAM可以认为是unsigned int,而LPARAM则是long

下面看函数体,先定义了几个变量,都是下面代码要用到的,用到再解释。

首先是一个switch语句,这个分支语句将会判断message的数值,对比语句块中的case对应的数值,相等就直接跳转到该case的代码。

WM_COMMAND

第一个case是WM_COMMAND,这个是一个define的宏:
#define WM_COMMAND 0x0111

所以实际是十六进制数0x0111。这个WM_COMMAND是在用户选择了某个菜单项,或者点击某个按钮,又或者按下某组加速键,就会收到该消息。
对于WM_COMMAND消息,WPARAM的低16位(wmId = LOWORD(wParam))表示id(菜单项id/按钮控件id/加速键id)。
高16位(wmEvent = HIWORD (wParam))则要根据触发消息的对象来确定
如果是菜单项触发的消息,则高16位wmEvent是0;
如果是加速键,wmEvent则是1;
如果是按钮,则wmEvent表示的是通知码,通俗的说就是按钮事件,比如是单击按钮BN_CLICKED还是双击按钮BN_DBLCLK
LPARAM,也是要根据触发消息的对象来确定,如果是按钮触发的消息,lparam就是按钮控件的句柄;其他对象(菜单项和加速键)触发的消息,lparam0
接下来是一个判断wmId的分支语句switch,第一个分支caseIDM_ABOUT,就是用户选择了菜单项的"关于"(或者加速键Alt+'/'),这个分支会使用DialogBox宏来创建一个模态对话框,然后break,这个break非常重要,千万不能忘记加,如果这里没有break,程序将会继续执行下面的
case IDM_EXIT的代码。DialogBox宏实际上是调用了DialogBoxParam函数。该函数第一个参数是进程实例hInst;第二个参数是窗口模板资源id;第三个参数是这个模态对话框的父窗口句柄,在这里就是主窗口的句柄了;第四个参数是该模态对话框的消息处理函数。第五个参数是要传递给模态窗口的WM_INITDIALOG消息的参数,估计没多大用,DialogBox宏直接省略了。
wmId
的第二个分支caseIDM_EXIT,就是点了退出菜单了,处理代码是"DestroyWindow
(hWnd);"这个DestroyWindowwindows系统API,作用是给参数中指定的hwnd窗口发送一个WM_DESTROY消息。
wmId
第三个分支是
default,就是当前面所有case都对不上的时候,最终的处理代码。这里的处理代码是调用DefWindowProc并退出函数。DefWindowProc函数顾名思义,就是windows系统提供的默认的消息处理函数,用于处理我们不关心的消息。
这个switch语句结束之后就是一个break,这个break是对应
case WM_COMMAND分支处理代码的结束。

WM_PAINT

这个消息是绘制消息,当窗口需要重绘的时候,我们就会收到消息。处理代码是先调用BeginPaint获取一个显示设备句柄hdc,对这个句柄进行各种绘制(目前并没有绘制代码)之后,调用EndPaint函数来结束绘制,他是和BeginPaint配套出现的。这两个函数的参数是一样的,第一个参数是窗口句柄;第二个参数是一个PAINTSTRUCT结构的变量的指针,但是BeginPaint是将相关信息写入到这个结构体中,而EndPaint则只是读取这个结构体的内容。同样执行完毕之后break

WM_DESTROY

这个消息前面提到,当我们决定退出程序的时候会调用DestroyWindow发送这个消息,然后现在接收到这个消息了,就要调用PostQuitMessage函数来发送一个WM_QUIT消息,然后我们在WinMain函数中的GetMessage消息循环看到了就会退出啦。

default分支

使用DefWindowProc默认窗口消息处理函数来处理其他不关心的消息。

About模态对话框消息处理函数

这个是用户定义的窗口消息处理函数,这个函数是在WndProc函数的WM_COMMAND分支的IDM_ABOUT分支的处理代码DialogBox创建模态对话框时用到的。这个对话框消息处理函数的原型和前面的WndProc基本一样,就不多说了。
函数体也大致相同,处理了两个消息:

WM_INITDIALOG

对话框初始化消息,在对话框显示之前可以进行一些初始化操作。一般返回TRUE,除非对于系统安排的默认焦点控件不满意,自己安排了新的焦点控件,那么可以返回FALSE。

WM_COMMAND

这个"关于"对话框没有菜单也没有加速键,只有一个"确定"按钮,所以没有再做分支,直接判断,当按下"确定"按钮或者"取消"按钮(或者是窗口右上角的X关闭按钮),就调用EndDialog函数来销毁这个模态对话框。这个EndDialog第一个参数是对话框句柄,就是About函数第一个参数;第二个参数是作为前面调用DialogBox的函数返回值。

"模态对话框"就是当这个对话框弹出之后,他的父窗口就没办法操作了,必须等到模态对话框关闭了才能继续操作,在某些线性流程需要等待用户处理结果的时候,就可以使用模态对话框;与之相对应的就是"非模态对话框",就是弹出之后不影响父窗口的操作,比如大多数文本编辑器的"查找"窗口,基本都是非模态的,这样方便一边搜索一边修改文档。

输出"hello world"

代码讲解了这么多节,现在就是真正要显示"hello world"了。请定位代码到"WndProc"函数的WM_PAINT分支:
    case WM_PAINT:

        hdc = BeginPaint(hWnd, &ps);

        // TODO: 在此添加任意绘图代...

        EndPaint(hWnd, &ps);

        break;

"// TODO: 在此添加任意绘图代码..."双斜杠"//"表示后面的内容是注释,如果有多行注释可以使用"/*...*/":
/*这是注释第一行
这是注释第二行
这是注释第三行*/
/*
*/之间的内容就是注释。
我们就在双斜杠注释这里添加代码:
    case WM_PAINT:

        hdc = BeginPaint(hWnd, &ps);

        // TODO: 在此添加任意绘图代码...

        TextOut(hdc , 0 , 0 , _T("hello world!") , 12);

        EndPaint(hWnd, &ps);

        break;

添加了一行代码,调用了TextOut来输出一行文本。
第一个参数就是BeginPaint获取到的显示设备句柄hdc
第二个参数和第三个参数是要输出文本的起始坐标xy
第四个参数是具体要输出的文本内容;
第五个参数是输出的文本内容的字符数。

输出效果:

字体挺丑的,因为使用的是系统默认字体,下一节(或者以后。。)会讲如何设置字体、字号、颜色等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值