Welcome

首页 / 软件开发 / C++ / 窗口刷新问题(WM_PAINT、BeginPaint、EndPaint的说明)

窗口刷新问题(WM_PAINT、BeginPaint、EndPaint的说明)2011-04-21 C++博客 OnTheWay在Windows API编程中,WM_PAINT是Windows窗口的一个重要消息,应用程序就是通过响应 这个消息来完成窗口的绘制。

The WM_PAINT message is generated by the system and should not be sent by an application.The system sends this message when there are no other messages in the application"s message queue

注意:WM_PAINT 消息是由系统产生,非要等应用程序的消息队列为空时才发送WM_PAINT消息 。

其实 系统会在很多的不同的机制下发送WM_PAINT消息,比如调用UpdateWindow函数,第一次创建 窗口,改变了窗口的大小,最大化,最小化等等。这些动作的产生都是有系统来控制的,应 用程序只是接收消息,并处理消息。

当Window检测到窗口被覆盖的地方需要恢复的时 候,它会向用户程序发送一个WM_PAINT消息,消息中包括了需要恢复的区域,然后由用户程 序来决定如何恢复被覆盖的内容。窗口过程收到WM_PAINT消息后,并不代表整个客户区都需 要被刷新,有可能客户区被覆盖的区域只有一小块,这个区域叫做“无效区域” ,程序只需要更新这个区域。与WM_TIMER消息类似,WM_PAINT消息也是一个低级别的消息, 虽然它不会像WM_TIMER消息一样被丢弃,但Windows总是在消息循环空的时候才把WM_PAINT放 入其中,实际上,Windows为每个窗口维护一个“绘图信息结构”,无效区域的坐 标就在其中,每当消息循环空的时候,如果Windows发现存在一个无效区域,就会放入一个 WM_PAINT消息。

无效区域的坐标并不附带在WM_PAINT消息的参数中,在程序中有其他 方法可以获取,WM_PAINT消息只是通知程序有个区域需要更新而已,所以Windows也不会同时 将两条WM_PAINT消息放入消息循环中,当Windows要放入一条WM_PAINT消息的时候,如果发现 已经存在一个无效区域了,那么它只需要把新旧两个无效区域合并计算出一个无效区域就可 以了,消息循环中还是只需要一条WM_PAINT消息。

如果程序在WM_PAINT消息中对客户 区刷新完毕后工作并没有结束,如果不使无效区域变得有效,Windows会在下一轮消息循环中 继续放入一个WM_PAINT消息,而不是根据程序是否执行了刷新过程,所以程序也可以不去刷 新客户区,而是简单地用一个ValidateRect函数直接让客户区变得有效,以此来“欺骗 ”Windows已经没有无效区域了,当Windows检查“绘图信息结构”的时候发 现没有了无效区域,也就不会继续发送WM_PAINT消息了。

那么“绘图信息结构 ”怎么获取呢?BeginPaint函数的第二个参数是一个绘图信息结构的缓冲区地址, windows会在这里返回绘图信息结构,结构中包含了无效区域的位置和大小,绘图信息结构的 定义如下:

typedef struct tagPAINTSTRUCT { // ps
HDC hdc;
BOOL fErase;
RECT rcPaint;
BOOL fRestore;
BOOL fIncUpdate;
BYTE rgbReserved[32];
} PAINTSTRUCT;