专栏导航
下一篇:无
本节前言
对于本节所讲解的知识,有可能,你会需要时不时地参考本专栏的其它文章。真的遇到了需要参考之前的文章的知识点,请你自行查阅。
我呢,也会提到一部分的参考课节。但是呢,你不应该依赖于我的主动提及。最好呢,你自己能够多去了解和查看本专栏目录。
学习本节所讲的知识,需要你事先了解过本章的完整代码。完整的代码,请参考下述文章链接。
本节,我们来讲解,本章代码是如何来处理 WM_PRINT 消息的。
本节的讲解,我会大段地抄录佩措尔德的教材。没办法,他写得太好了,我很难写出别的什么样子来。
一. WM_PRINT 消息
窗口过程函数 WndProc 所处理的另一条消息是 WM_PRINT 。这条消息在 Windows 编程中非常重要。当窗口的客户区部分或全部"无效"且必须"更新"时,应用程序将得到此通知。这也就意味着窗口必须被"重绘"。
何种情况下,客户区会变为无效?当窗口被首次创建时,整个客户区都是无效的,因为此时应用程序尚未在该窗口上绘制任何东西。第一条 WM_PRINT 消息将指示窗口过程在窗口客户区进行绘制。
关于第一条 WM_PRINT 消息,它通常在应用程序调用 WinMain 中的 UpdateWindow 时出现。
我认为,,第一条 WM_PRINT 消息出现的时机,大家应该把它给记下来。
在之前,讲解 WM_CREATE 消息的时候,我讲解了它的产生时机。第一条 WM_CREATE 消息,一般是在 Windows 程序的 WinMain 函数中,调用 CreateWindow 函数来创建窗口时产生。产生 WM_CREATE 消息时,程序正处在 CreateWindow 函数中,尚未返回。
而在这里,我们需要记住第一条 WM_PRINT 消息的产生时机。
为啥要记住呢?
因为,以后,我们很可能会需要去学习 WIndows 程序设计的一个重要的 C++ 类库,MFC 。
MFC,包含了对 WIndows API 函数与相关数据结构的封装,很多在 WIndows API 程序中会出现的东西,在 MFC 中,你都见不到了。
为了在以后学习 MFC 的时候,能够方便许多,能够更好地理解 MFC 的运行机制,此时,你在学习 Windows API 程序设计的时候,那就需要你尽量地理解好许多的基础知识了。
此处, 第一条 WM_PRINT 消息的产生时机,这就是你需要去记住的。
我们接着讲。
在调整 HelloWin 窗口的尺寸时,客户区也会变为无效。你可能还记得,在前面程序中,我们将 HelloWin 的 WNDCLASS 结构体变量 wndclass 的 style 字段设置成了【CS_HREDRAW | CS_VREDRAW】。这就表示,当窗口的横向尺寸和纵向尺寸发生变化时,整个窗口都应该宣布变为无效。在此之后,窗口过程函数会接收到一条 WM_PRINT 消息。
如果先最小化 HelloWin,然后再将窗口恢复到原先的尺寸,Windows 并不会保存客户区的内容。因为,在图形环境中,这需要保存的内容太多了。Windows 所采取的策略是,宣布窗口无效。窗口过程接收到 WM_PRINT 消息以后,会自行恢复窗口的内容。
在屏幕中拖动窗口导致窗口之间发生重叠时,WIndows 并不会负责保存被另一个窗口覆盖的区域。当被覆盖区域在后来不再被遮挡时,窗口被标记为无效。窗口过程会接收到一条 WM_PRINT 消息,并对窗口的内容进行重绘。
对 WM_PRINT 消息的处理,几乎总是从调用 BeginPaint 函数开始,代码如下。
hdc = BeginPaint(hwnd, &ps);
而以 EndPaint 函数结束,代码如下。
EndPaint(hwnd, &ps);
在这两个函数调用中,第一个参数均为程序的窗口句柄,而第二个参数均为指向一个类型为 PAINTSTRUCT 结构体的指针。PAINTSTRUCT 结构体包含一些窗口过程用来对客户区进行绘制的信息。在下一章,我们将介绍该结构体中的各个字段。而现在,,我们只管在 BeginPaint 和 EndPaint 函数中使用它。
在 BeginPaint 调用期间,如果客户区的背景尚未被擦除,则 Windows 会对其进行擦除。擦除背景时使用的画刷是在用于注册窗口类的 WNDCLASS 结构体中的 hbrBackground 字段中指定的。
在 HelloWin 中,所使用的画刷是库存的白色画刷,即 Windows 会将窗口的背景清除为白色。
BeginPaint 调用将使整个客户区有效,并返回一个"设备环境句柄"。
设备环境,其英文为 Device Context,是指物理输出设备(如视频显示器)及其设备驱动程序。
在 Prosise 的 MFC 教材中,他将设备环境称作设备描述表,并将设备环境句柄称作设备描述表句柄。
在国内的许多的 Windows 程序设计教材中,也将设备环境称作设备描述表。
在本专栏中,我在写作 Win32 章节时,我会与佩措尔德先生的教材保持一致,采用"设备环境"的翻译术语;而在写作 MFC 章节时,会与 Prosise 的教材保持一致,采用"设备描述表"的翻译术语。
我们需要设备环境句柄以在窗口的客户区显示文本和图形。使用由 BeginPaint 函数返回的设备环境句柄,是无法在客户区以外的区域进行绘制的。EndPaint 函数用于释放设备环境句柄,以使其无效。
对资源的申请与释放,这应该是成对出现的东西。在学习 WIndows 程序设计的时候,你应该可以多次接触到申请资源与释放资源的操作。
我认为,这种申请与释放资源的机制,算是编程中的一种难点了。这会儿,我对此,还掌握得不好。希望你在学习的时候,能够逐渐地掌握申请与释放资源的知识吧。
这种申请资源与释放资源的机制,让 Windows 程序设计显得十分专业。学好这样的东西,对于你的编程技能,会是很好的一种锻炼与提升。
如果一个窗口过程不对 WM_PRINT 消息进行处理(这是极其罕见的),则这类消息必须交给 DefWindowProc 来处理。DefWindowProc 所做的只是简单地依次调用 BeginPaint 和 EndPaint,以使客户区变为有效。
当 WndProc 调用完 BeginPaint 之后,它对 GetClientRect 进行调用。
GetClientRect(hwnd, &rect);
该函数的第一个参数是程序的窗口句柄。第二个参数为指向类型为 RECT 的矩形结构体的指针。该结构具有四个类型为 LONG 型的字段,名称分别为 left,top,right,bottom 。
关于 RECT 结构体类型,我们之前有讲解过,文章链接如下。
GetClientRect 函数将依据窗口尺寸来对这四个字段进行设置。其中,left 和 top 字段总会被设置为 0,而 right 和 bottom 字段会分别被设置为客户区的宽度和高度,单位是像素。
WndProc 并未对该 RECT 结构体做任何处理,而仅仅是将其赋给一个指针而作为 DrawText 函数的第四个参数。
图1
DrawText 函数所实现的功能与其名称一致,即绘制文本。由于该函数完成的是绘制功能,因此其第一个参数为由 BeginPaint 函数所返回的设备环境句柄。第二个参数是所要绘制的文本内容。第三个参数设为 -1,表示该文本字符串以 0 作为结尾。
DrawText 函数的最后一个参数是一组位标记,这些标记的定义位于 WinUser.h 中。DrawText 函数完成的是输出显示文本的功能,看起来,DrawText 函数应该属于 GDI 函数。但是呢,实际上,它是一个相当高层的绘制函数,因而属于用户模块。
这些标记指示所显示的文本应在第四个参数所限定的矩形区域内单行显示,并且水平和垂直居中。按照这种方式对该函数进行调用,就会使字符串 "Hello, Windows Program !" 显示在客户区的中央。
在这里,标记 DT_SINGLELINE 指示所显示的文本字符串 "Hello, Windows Program !" 在第四个参数所限定的矩形区域内单行显示。
标记 DT_CENTER 指示所显示的文本字符串 "Hello, Windows Program !" 在第四个参数所限定的矩形区域内水平居中显示。
标记 DT_VCENTER 指示所显示的文本字符串 "Hello, Windows Program !" 在第四个参数所限定的矩形区域内垂直居中显示。
无论何时,当客户区变为无效时(如调整窗口尺寸时),WndProc 都将接收到一条新的 WM_PRINT 消息。WndProc 通过调用 GetClientRect 函数可以获得更新后的窗口尺寸,并再次将这行文本显示在调整尺寸后的窗口客户区的中央。
总 结
这一节,写得实在是没啥意思。因为,我想不出要咋去组织语言来写。
所以呢,只好大段抄录了。
单纯的抄录,实在是没意思啊。
专栏导航
下一篇:无