本文转自:http://hi.baidu.com/sunkanghome/blog/item/90f3d3893b5923b60f244428.html
WM_PAINT是Windows窗口系统中一条重要的消息, 应用程序通过处理该消息实现在窗口上的绘制工作。 1. 系统何时发送WM_PAINT消息?
InvalidateRect和InvalidateRgn把指定的区域加到窗口的Update Region中,当应用的消息队列没有其他消息时,如果窗口的Update Region不为空时,系统就会自动产生WM_PAINT消息。 系统为什么不在调用Invalidate时发送WM_PAINT消息呢?又为什么非要等应用消息队列为空时才发送WM_PAINT消息呢?这是因为系统把在窗口中的绘制操作当作一种低优先级的操作,于是尽可能地推后做。 不过这样也有利于提高绘制的效率:两个WM_PAINT消息之间通过InvalidateRect和InvaliateRgn使之失效的区域就会被累加起来,然后在一个WM_PAINT消息中一次得到更新,不仅能避免多次重复地更新同一区域,也优化了应用的更新操作。 这种通过InvalidateRect和InvalidateRgn来使窗口区域无效,依赖于系统在合适的时机发送WM_PAINT消息的机制实际上是一种异步工作方式,也就是说,在无效化窗口区域和发送WM_PAINT消息之间是有延迟的;有时候这种延迟并不是我们希望的,这时我们当然可以在无效化窗口区域后利用SendMessage 发送一条WM_PAINT消息来强制立即重画,但不如使用Windows GDI为我们提供的更方便和强大的函数:UpdateWindow和RedrawWindow。 UpdateWindow会检查窗口的Update Region,当其不为空时才发送WM_PAINT消息;RedrawWindow则给我们更多的控制:是否重画非客户区和背景,是否总是发送WM_PAINT消息而不管Update Region是否为空等。 --------------------------------------------------------------------------------
BeginPaint和WM_ERASEBKGND消息也有关系。当窗口的Update Region被标志为需要擦除背景时,BeginPaint会发送WM_ERASEBKGND消息来重画背景,同时在其返回信息里有一个标志表明窗口背景是否被重画过。 当我们用InvalidateRect和InvalidateRgn来把指定区域加到Update Region中时,可以设置该区域是否需要被擦除背景,这样下一个BeginPaint就知道是否需要发送WM_ERASEBKGND消息了。 另外要注意的一点是,BeginPaint只能在WM_PAINT处理函数中使用。
补充几点: 1.WM_Paint 是一个被动消息,不能通过普通的方法简单的 sendmessage WM_paint 了事 2.sendmessage 可以将消息发送到消息队列;但windows会自动判断是否存在无效的画图区域; 3.可以使用 InvalidateRect 等几个APi将屏幕上任意一个个矩形区域设置为无效区域,在UpdateWindow后调用后,windows会自动查找是否存在无效,并重画,该矩形区域; ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 当窗口需要重绘时,系统会为窗口发送这个消息,比如一个窗口被另一个窗口挡住、一个窗口被移走而下面的窗口露出来,还有一个窗口从最小化中恢复、改变大小,移动位置。。。。等等。 程序也可以显示的调用Invalidate等函数要求窗口重绘,那么也会触发WM_PAINT。 +++++++++++++++++++++++++++++++++++++++++++++++++ 问题: 我在视图画的图象或者文字,当窗口改变后为什么不见了?OnDraw()和OnPaint()两个都是解决上面的问题,有什么不同?
void CView::OnPaint() { CPaintDC dc(this); OnPreparDC(&dc); OnDraw(&dc); //调用了OnDraw }
void CMyView::OnDraw( CDC* pDC ) { CMyDoc* pDoc = GetDocument(); CString s = pDoc->GetData(); // Returns a CString CRect rect; pDC->SetTextAlign( TA_BASELINE | TA_CENTER ); pDC->TextOut( rect.right / 2, rect.bottom / 2, s, s.GetLength() ); } 用OnDraw维护视图的客户区(例如我们通过鼠标在视图中画图)。 当然你也可以不按照上面规律来,只要达到目的并且没有问题,怎么干都成。
++++++++++++++++++++++++++++++++++++ Vc++中OnDraw和OnPaint有什么区别? 前者是可以响应WM_PAINT消息,后者是专门的响应WM_PAINT的消息映射函数, 前者是在CView中操作画图的函数。但是最终的功能都是onPaint实现的,因为OnDraw也是OnPaint函数调用的。 函数原形如下: CPaintDC dc(this); |