窗口绘制

WM_PAINT 消息:

    Windows通过发送 WM_PAINT 消息来通知窗口过程其客户区需要重绘。大多数 Windows 程序在 WinMain 函数初始化

    过程中会在进入消息循环之前调用 UpdateWindow() 函数。这将会向窗口过程函数( WndProc() )发送最初的 WM_PAINT

    消息,该消息通知窗口过程绘制客户区。

    在以下任何事件发生时,窗口过程都会收到一条 WM_PAINT 消息;

  • 用户移动一个窗口,导致原来被遮挡的部分窗口暴露出来。
  • 用户调整窗口大小。
  • 程序调用 ScrollWindow() 或 ScrollDC() 函数滚动客户区。
  • 程序调用 InvalidateRect() 或 InvalidateRgn() 函数显示生成 WM_PAINT 消息。
   某些情况下,当客户区的一部分被临时覆盖时,Windows 会试图保存被覆盖的这部分,以便将来恢复时使用。这并不是每次

   都可以成功。

   在以下情形,Windows 有时 会发生一条 WM_PAINT 消息。

  • Windows 关闭一个覆盖了部分窗口过程的对话框或消息框。
  • 下拉菜单被拉下然后收回。
  • 显示提示信息。
    少数情况下,Windows 总是会保存被覆盖部分的显示内容,然后再恢复。

    这些情况如下:

  • 鼠标指针在客户区内移动。
  • 在客户区内拖到图标。

有效矩形和无效矩形:

尽管窗口过程必须能够在收到 WM_PAINT 消息时更新整个客户区,但通常它只需要更新其中的一部分。最明显的例子是

当一个对话框覆盖了客服区的一部分时:当对话框关闭时,只有先前被覆盖的那个矩形部分需要重新绘制。

需要重新绘制的部分被称为“无效区域”或“更新区域”在客户区中有一个无效区域将导致 Windows 在应用程序的消息

队列中放置一条 WM_PAINT 消息。只有当程序客户区的一部分失效时,窗口过程才会接受到 WM_PAINT 消息。

Windows 内部为每一个窗口都保存了一个“绘制信息结构”(PAINTSTRUCT)。该结构保存着一个可以覆盖该无效区域的最小

矩形的坐标和一些其他的信息。这个最小区域称为“无效矩形”。如果在窗口过程处理一条等候处理 WM_PAINT 消息之前,

客户区的另外一部分也失效了,那么 Windows 将计算出一个覆盖这两个失效部分的新的无效区域和无效矩形,并更新绘制

信息结构中的数据。也就是说将仍只有一条 WM_PAINT 消息。

窗口过程可以通过 InvalidateRect() 函数来强制使自己的客户区的一个矩形失效,也可以调用 ValidateRect() 函数来强制使客户区变的有效。如果是让整个无效区域都有效,那么消息队列中的 WM_PAINT 消息就会被删除。

这两个函数在有时候是很有用处的。

窗口过程在处理 WM_PAINT 消息时,在调用BeginPaint() 函数时,整个客户区会变有效的 。


设备环境:

当程序完成对客户区的绘制后,它必须释放设备环境句柄。释放后该句柄将不再有用。程序必须在处理同一条消息的过程中获取

句柄和释放句柄。你不能在两条消息中间传递一个设备环境句柄,唯一的例外是通过调用 CreateDC() 函数创建设备环境。

关于设备环境句柄在 HELLOWIN 程序中已经详细介绍到了,这里就不介绍了。


获取设备环境句柄:方法一

这种方法可以在处理 WM_PAINT 消息时使用。这关系到两个函数:BeginPaint() 和 EndPaint() 。这两个函数都需要

两个参数:一个是窗口的句柄,这是消息处理过程的参数:另一个是一个类型为 PAINTSTRUCT 结构的变量的地址。

程序通常将该结构体变量命名为 ps 。

在处理 WM_PAINT 消息时,窗口过程首先调用BeginPaint() 函数,该函数通常会擦去无效区域的背景以便绘图。

它同时还会填充 ps 结构的各个字段。函数的返回值就是设备环境句柄。通常会将它保存在一个名为 hdc 的变量中。

窗口过程在处理 WM_PAINT 消息时必须成对的调用 BeginPaint() 和 EndPaint() 。如果窗口过程不处理 WM_PAINT 

消息,该消息就会被传送给 Windows 默认的窗口过程 DefWindowProc 。

绘制信息结构:

PAINTSTRUCT 结构体如下:

typedef struct tagPAINTSTRUCT { 
HDC hdc; 
BOOL fErase; 
RECT rcPaint;
BOOL fRestore;
BOOL fIncUpdate;
BYTE rgbReserved[32]; 
} PAINTSTRUCT, *PPAINTSTRUCT; 
hdc 是用于绘制的句柄,
fErase 如果为非零值则擦除背景,否则不擦除背景,
rcPaint 通过制定左上角和右下角的坐标确定一个要绘制的矩形范围,该矩形单位相对于客户区左上角,
后面三个参数都是系统预留的,编程一般用不到。当程序调用 BeginPaint() 函数时,Windows 将自动填充这个结构体中的字段。

      程序只能使用前三个字段,其他的供 Windows 内部使用。

     在大多数情况下,fErase 字段将被设置为 FALSE(即0),这意味着 Windows 在先前的 BeginPaint() 函数中已经擦除了

     无效区域的背景。在 WINMAIN 初始化时,用于注册窗口类的 WNDCLASS 结构中的 hbrBackground 字段指定了一个

     画刷, Windows 就使用这个画刷来擦除背景。


获取设备环境句柄:方法二

尽管最后在程序处理 WM_PAINT 消息时才更新整个客户区,但有时也会发现在处理非 WM_PAINT 消息时绘制部分客户区

也是很有用的。这时你可以调用 GetDC() 函数来获得窗口客户区的设备环境句柄,使用完成后也必须调用 ReleaseDC() 函数将

它释放:

hdc = GetDC(hwnd);
releaseDC(hwnd,hdc);

 这个函返回的句柄和 BeginPaint() 函数返回的有所不同,从 GetDC() 返回的设备环境句柄中的裁剪矩形是整个客户区。这意味

着你可以在客户区的任意部分绘制,而不局限于无效矩形。另外,GetDC() 函数将不会使无效区域有效化。如果想使整个客户区

有效,可以调用 ValidateRect() 函数。







猜你喜欢

转载自blog.csdn.net/qq_41413835/article/details/80685282
今日推荐