绘制和重绘,有效矩形和无效矩形
当用户在屏幕移动其他程序的窗口时,可能会遮住当前程序的部分窗口。Windows 不会保存被遮住的那部分窗口,当其他程序的窗口被移开时,Windows 会要求你的程序重新绘制刚才被遮住的部分区域。如果你自己不重绘,Windows 是不会管的。
Windows 是一个消息驱动的系统,它使用两种方式把各种事件通知给应用程序:
- 把消息放到应用程序的消息队列中,让程序自己通过 GetMessage 函数获取;
- 向窗口直接发送消息。
WM_PAINT 消息
WM_PAINT 消息表示绘制窗口的客户区。窗口过程会经常收到 WM_PAINT 消息,而且能够在必要的时候绘制客户区。
以下任何一个事件发生时,窗口过程都会收到一条 WM_PAINT 消息:
- 用户移动一个窗口,导致原来被遮住的部分窗口暴露出来。
- 用户调整窗口的大小(当窗口类中 style 字段的值设定为 CS_HREDRAW | CS_VREDRAW 时)。
- 客户区滚动条滚动时。
- 当然,你可以可以调用相应的函数强制生成一条 WM_PAINT 消息。
注意:窗口类中 style 字段的值经常被设定为CS_HREDRAW | CS_VREDRAW
,只有这样,调整窗口宽度或高度时才会发生重绘。上节我们在客户区的中间位置输出一段文本,这是一个明显的例子,如果 style 字段的值不是 CS_HREDRAW | CS_VREDRAW,那么调整窗口大小时文本就不会自动调整,也就是不在客户区中间了。
在少数情况下,Windows 总是会保存被覆盖的部分窗口,然后再恢复,例如:
- 鼠标指针在客户区内移动。
- 在客户区内拖动图标。
读者需要记住,在Windows中一切界面都是绘图,一旦界面发生改变,就需要重新绘制。
有效矩形和无效矩形
Windows 一般不重绘整个客户区,而是绘制客户区的一部分。最明显的一个例子是当一个对话框覆盖了客户区的一部分时,对话框关闭时,只有先前被覆盖的那个矩形部分需要重新绘制。
需要重新绘制的部分被称为“无效区域”或“更新区域”。在客户区中有一个无效区域将导致 Windows 向应用程序队列中放置一条 WM_PAINT 消息。也就是说,只有当客户区的一部分失效时,窗口过程才会接收到 WM_PAINT 消息。
无效区域有时候是矩形,有时候是圆、多边形等,但总有一个最小的矩形可以覆盖整个无效区域,如下图所示:
上图中,灰色阴影表示无效区域,红色边框表示最小矩形。这个最小的矩形,就称为无效矩形。Windows 会自动保存无效矩形的坐标和大小,无需我们操心,当发生重绘时,总是重绘整个无效矩形区域。
当程序处理完 WM_PAINT 消息,无效矩形就会变成有效的,整个客户区也就有效了。