WM_PAINT 消息:
Windows通过发送 WM_PAINT 消息来通知窗口过程其客户区需要重绘。大多数 Windows 程序在 WinMain 函数初始化
过程中会在进入消息循环之前调用 UpdateWindow() 函数。这将会向窗口过程函数( WndProc() )发送最初的 WM_PAINT
消息,该消息通知窗口过程绘制客户区。
在以下任何事件发生时,窗口过程都会收到一条 WM_PAINT 消息;
- 用户移动一个窗口,导致原来被遮挡的部分窗口暴露出来。
- 用户调整窗口大小。
- 程序调用 ScrollWindow() 或 ScrollDC() 函数滚动客户区。
- 程序调用 InvalidateRect() 或 InvalidateRgn() 函数显示生成 WM_PAINT 消息。
都可以成功。
在以下情形,Windows 有时 会发生一条 WM_PAINT 消息。
- 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;
程序只能使用前三个字段,其他的供 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() 函数。