您的位置:首页 > 大数据 > 人工智能

3.1.11 WM_PAINT消息

2016-08-16 13:40 246 查看
 摘录于《Windows程序(第5版,珍藏版).CHarles.Petzold 著》P56、P64

        WM_PAINT消息在 Windows 编程中极其重要。当窗口的客户区的部分或全部“无效”且必须“更新”时,应用程序将得到此通知。这也就意味着窗口必须被“重绘”。

        但何种情况下客户区会变为无效?当窗口被首次创建时,整个客户区都是无效的,因为此时应用程序尚未在该窗口上绘制任何东西。第一条 WM_PAINT 消息(通在应用程序调用 WinMain 中的 UpdateWindow 时出现)将指示窗口过程在窗口客户区进行绘制。

        在调整 HELLOWIN 窗口的尺寸时,客户区也会变为无效。你可能还记得在前面的程序中,我们将 HELLOWIN 的 wndclass 结构的 style 字段设为了标记 CS_HREDRAW 和 CS_VREDRAW。这就指示 Windows 当窗口尺寸发生变化时,整个窗口都应宣布无效。在此之后,窗口过程将收到一条 WM_PAINT 消息。

        如果先最小化 HELLOWIN,然后再将窗口恢复到原先的尺寸,Windows并不会保存客户区的内容。在图形环境中,这种情况下需要保存的数据太多了。对此, Windows 采取的策略是宣布窗口无效。窗口过程接收 WM_PAINT 消息后,会自行恢复窗口的内容。

        在屏幕中拖动窗口导致窗口之间发生重叠时,Windows 并不负责保存被另一个窗口覆盖的区域。当被覆盖的区域在后来不再被遮挡时,窗口被标记为无效。窗口过程会收到一条 WM_PAINT 消息,并对窗口的内容进行重绘。

        对 WM_PAINT 消息的处理几乎总是从调用 BeginPaint 函数开始:

[cpp] view
plain copy

hdc = BeginPaint (hwnd, &ps);  

        而以调用 EndPaint 函数结束:

[cpp] view
plain copy

EndPaint (hwnd, &ps);  

        在这两个函数调用中,第一个参数均为程序的窗口句柄,而第二个参数均为指向一个类型为 PAINTSTRUCT 结构的指针。PAINTSTRUCT 结构包含一些窗口过程用来对客户区进行绘制的消息。

        在 BeginPaint 调用期间,如果客户区的背景尚未被擦除,则 Windows 会对其进行擦除。擦除背景时使用的画刷是在用于注册窗口类的 WNDCLASS 结构中 hbrBackground 字段中指定的。在 HELLOWIN 这个例子中,所使用的画刷是一个库存的白色画刷,即 Windows 会将窗口背景清除为白色。 BeginPaint 调用将使整个客户区有效,并返回一个“设备环境句柄”。设备环境(device
context)是指物理输出设备(如视频显示器)及其设备驱动程序。我们需要设备环境句柄以在窗口的客户区显示文本和图形。使用由 BeginPaint 函数返回的设备环境句柄,是无法在客户区以外的区域进行绘制的。EndPaint 函数用于释放设备环境句柄,以使其无效。

        如果一个窗口过程不对 WM_PAINT 消息进行处理(这事极其罕见的),则该类消息必须交给 DefWinowProc 来处理。DefWindowProc 所做的只是简单地依次调用 BeginPaint 和 EndPaint,以使客户区变为有效。

        当 WndProc 调用完 BeginPaint 之后,它对 GetClientRect 进行调用。

[cpp] view
plain copy

GetClientRect (hwnd, &rect);  

        该函数的第一个参数是程序的窗口句柄。第二个参数为指向类型为 RECT 的矩形结构的指针。该结构具有4个类型为 LONG 的字段,名称分别为 left、top、right 和 bottom。GetClientRect 函数将依据窗口尺寸来对这4个字段进行设置。其中,left 和 top 字段总是会被赋为0,这样 right 和 bottom 字段就分别表示以像素为单位的客户区的宽度和高度。

        WndProc 并未对该 RECT 结构做任何处理,而仅是将其赋给一个指针而作为 DrawText 函数的第四个参数:

[cpp] view
plain copy

DrawText (hdc, TEXT ("Hello, Windows 98!"), -1, &rect,  

                   DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;  

        DrawText 函数所实现的功能与其名称一致,即绘制文本。由于该函数完成的是绘制功能,因此其第一个参数为由 BeginPaint 函数所返回的设备环境句柄。第二个参数是所要绘制的文本内容。第三个参数被设为-1,表示该文本字符串以 0 作为结尾。

        DrawText函数的最后一个参数是一组位标记,这些位标记的定义位于 WINUSER.H 中。(尽管由于 DrawText 完成的是输出的显示而看起来像是一个 GDI 函数,但由于它是一个相当高层的绘制函数,因此实际上属于用户模块。)这些标记指示所显示的文本应在由第四个参数所限定的矩形区域内单行显示,并且水平和垂直居中。按照这种方式对该函数进行调用,就会使字符串“Hello,Windows 98!"显示在窗口客户区的中央。

        无论何时当客户区变为无效时(如调整窗口尺寸时),WndProc 都将接收到一条新的 WM_PAINT 消息。WndProc 通过调用 GetClientRect 函数可以获得更新后的窗口尺寸,并再次将这行文本显示在改变后的窗口的中央。

       大多数 Windows 程序在 WinMain 函数初始化过程中会在进入消息循环之前调用 UpdateWindow 函数。Windows 利用这个机会向窗口过程发送最初的 WM_PAINT 消息。这个消息通知窗口过程绘制客户区。此后,窗口过程需要在几乎任何时间都能够处理新收到的 WM_PAINT 消息,而且能够在必要时重绘整个客户区。在以下任何一个事件发生时,窗口过程都会收到一条 WM_PAINT 消息:
用户移动一个窗口,导致原来被遮盖的部分窗口暴露出来。
用户调整窗口的大小(当窗口的类型设定为 CS_HREDRAW 和 CS_VREDRAW 值时)。
程序调用 ScrollWinow 或 ScrollDC 函数滚动客户区。
程序调用 InvalidateRect 或 InvalidateRgn 函数 显式生成 WM_PAINT 消息。

        在某些情况下,当客户区的一部分被临时覆盖时,Windows 会试图保存被覆盖的这部分,以便将来恢复时使用。这并不是每次都能成功。在以下情形,Windows 有时会发送一条 WM_PAINT 消息:
Windows 关闭一个覆盖了部分窗口的对话框或消息框。
下拉菜单被拉下然后收回。
显示提示信息。

        在少数情况下, Windows 总是会保存被覆盖部分的显示内容,然后再恢复。这些情况如下:
鼠标指针在客户区内移动。
在客户区内拖动图标。
        处理 WM_PAINT 消息需要你改变对于视频输出的概念。你的程序应该收集并保存所有用于绘制客户区的信息,但是只在需要时进行绘制——当收到 WM_PAINT 消息时。如果程序需要在其他时候更新客户区,可以强制 Windows 生成 WM_PAINT 消息。这看上去貌似饶了一个弯,但是程序的结构会因此而受益。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: