WM_PAINT 消息详解
来源:互联网 发布:js 对象 属性 编辑:程序博客网 时间:2024/06/05 21:09
本文转自:http://hi.baidu.com/sunkanghome/blog/item/90f3d3893b5923b60f244428.html
WM_PAINT是Windows窗口系统中一条重要的消息,
应用程序通过处理该消息实现在窗口上的绘制工作。
1. 系统何时发送WM_PAINT消息?
系统会在多个不同的时机发送WM_PAINT消息:当第一次创建一个窗口时,当改变窗口的大小时,当把窗口从另一个窗口背后移出时,当最大化或最小化窗口时,等等,这些动作都是由系统管理的,应用只是被动地接收该消息,在消息处理函数中进行绘制操作;大多数的时候应用也需要能够主动引发窗口中的绘制操作,比如当窗口显示的数据改变的时候,这一般是通过InvalidateRect和 InvalidateRgn函数来完成的。
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是否为空等。
--------------------------------------------------------------------------------
2. BeginPaint
BeginPaint和WM_PAINT消息紧密相关。试一试在WM_PAINT处理函数中不写BeginPaint会怎样?程序会像进入了一个死循环一样达到惊人的CPU占用率,你会发现程序总在处理一个接一个的WM_PAINT消息。这是因为在通常情况下,当应用收到WM_PAINT消息时,窗口的Update Region都是非空的(如果为空就不需要发送WM_PAINT消息了),BeginPaint的一个作用就是把该Update Region置为空,这样如果不调用BeginPaint,窗口的Update Region就一直不为空,如前所述,系统就会一直发送WM_PAINT消息。
BeginPaint和WM_ERASEBKGND消息也有关系。当窗口的Update Region被标志为需要擦除背景时,BeginPaint会发送WM_ERASEBKGND消息来重画背景,同时在其返回信息里有一个标志表明窗口背景是否被重画过。
当我们用InvalidateRect和InvalidateRgn来把指定区域加到Update Region中时,可以设置该区域是否需要被擦除背景,这样下一个BeginPaint就知道是否需要发送WM_ERASEBKGND消息了。
另外要注意的一点是,BeginPaint只能在WM_PAINT处理函数中使用。
--------------------------------------------------------------------------------
补充几点:
1.WM_Paint 是一个被动消息,不能通过普通的方法简单的 sendmessage WM_paint 了事
这是不行的;但通过消息由程序员引发不是不可能;通过几个特殊的常数可以做到,不过要到delphi下找
2.sendmessage 可以将消息发送到消息队列;但windows会自动判断是否存在无效的画图区域;
如果存在无效的画图区域,则可能会重画,反之则弃用该消息.
3.可以使用 InvalidateRect 等几个APi将屏幕上任意一个个矩形区域设置为无效区域,在UpdateWindow后调用后,windows会自动查找是否存在无效,并重画,该矩形区域;
++++++++++++++++++++++++++++++++++++++++++++++++++++++
当窗口需要重绘时,系统会为窗口发送这个消息,比如一个窗口被另一个窗口挡住、一个窗口被移走而下面的窗口露出来,还有一个窗口从最小化中恢复、改变大小,移动位置。。。。等等。 程序也可以显示的调用Invalidate等函数要求窗口重绘,那么也会触发WM_PAINT。
当然操作系统不知道你的窗口上将出现什么画面,那是应用程序应该干的事情,那么这个消息的作用就是告诉应用程序,你该重画你的窗口了。CWnd的重画消息。简单的说用于重画窗体。
前提知识:Windows中的看到的窗口 等 都是“画”上去的。
当程序调用Invalid()等函数的时候,产生一个WM_PAINT消息给父层。
操作系统的消息处理机制接收到这个消息后,
对设置的区域进行重画操作。
当重画的内容有变化时,也就是一种更新。
+++++++++++++++++++++++++++++++++++++++++++++++++
问题:
我在视图画的图象或者文字,当窗口改变后为什么不见了?OnDraw()和OnPaint()两个都是解决上面的问题,有什么不同?
因为当你的窗口改变后,会产生无效区域,这个无效的区域需要重画。一般Windows回发送两个消息WM_PAINT(通知客户区有变化)和WM_NCPAINT(通知非客户区有变化)。非客户区的重画系统自己搞定了,而客户区的重画需要我们自己来完成。这就需要OnDraw()或OnPaint()来重画窗口。
OnDraw()和OnPaint()有什么区别呢?首先:我们先要明确CView类派生自CWnd类。而OnPaint()是CWnd的类成员,同时负责响应WM_PAINT消息。OnDraw()是CVIEW的成员函数,并且没有响应消息的功能。这就是为什么你用VC的程序代码时,在视图类只有OnDraw没有OnPaint的原因。
其次:要想在屏幕上绘图或显示图形,首先需要建立设备环境DC。其实DC是一个数据结构,它包含输出设备(不单指你17寸的纯屏显示器,还包括打印机之类的输出设备)的绘图属性的描述。MFC提供了CPaintDC类和CWindwoDC类来实时的响应,而CPaintDC支持重画。
当视图变得无效时(包括大小的改变,移动,被遮盖等等),Windows 将 WM_PAINT 消息发送给它。该视图的 OnPaint 处理函数通过创建 CPaintDC 类的DC对象来响应该消息并调用视图的 OnDraw 成员函数。通常我们不必编写重写的 OnPaint 处理成员函数。
///CView默认的标准的重画函数
void CView::OnPaint()
{
CPaintDC dc(this);
OnPreparDC(&dc);
OnDraw(&dc); //调用了OnDraw
}
既然OnPaint最后也要调用OnDraw,因此我们一般会在OnDraw函数中进行绘制。下面是一个典型的程序
///视图中的绘图代码首先检索指向文档的指针,然后通过DC进行绘图调用。
void CMyView::OnDraw( CDC* pDC )
{
CMyDoc* pDoc = GetDocument();
CString s = pDoc->GetData(); // Returns a CString CRect rect;
GetClientRect( &rect );
pDC->SetTextAlign( TA_BASELINE | TA_CENTER );
pDC->TextOut( rect.right / 2, rect.bottom / 2, s, s.GetLength() );
}
因此我们一般用OnPaint维护窗口的客户区(例如我们的窗口客户区加一个背景图片),
用OnDraw维护视图的客户区(例如我们通过鼠标在视图中画图)。
当然你也可以不按照上面规律来,只要达到目的并且没有问题,怎么干都成。
补充:我们还可以利用Invalidate(),ValidateRgn(),ValidateRect()函数强制的重画窗口
++++++++++++++++++++++++++++++++++++
Vc++中OnDraw和OnPaint有什么区别?
前者是可以响应WM_PAINT消息,后者是专门的响应WM_PAINT的消息映射函数,
前者是在CView中操作画图的函数。但是最终的功能都是onPaint实现的,因为OnDraw也是OnPaint函数调用的。
函数原形如下:
OnPaint()
{
CPaintDC dc(this);
OnPreapareDC(&dc);
OnDarw(&dc);
}
- WM_Paint 消息详解
- WM_PAINT 消息详解
- WM_Paint 消息详解
- WM_PAINT消息详解
- WM_Paint消息详解
- WM_PAINT消息详解
- WM_Paint 消息详解
- WM_PAINT消息详解
- windows程序设计(2):WM_PAINT消息详解
- WM_PAINT消息
- WM_PAINT消息
- WM_PAINT消息
- WM_PAINT消息
- WM_PAINT消息
- WM_PAINT消息
- WM_PAINT消息
- WM_PAINT消息
- WM_PAINT消息
- flex 中 bindable的意义
- PulseAudio Debugging
- 运算符优先级小记
- Java堆内存Heap与非堆内存Non-Heap
- flex常用网站
- WM_PAINT 消息详解
- 常见面试算法小题目分享~更新ing~
- Population produce opportunities and challenges
- 加载页面访问速度 优化
- winpcap 枚举网卡设备Demo
- Vim 实用技术,第 1 部分: 实用技巧
- 泛型学习笔记
- enable_irq_wake
- Google Python 风格指南