关于WM_PAINT,窗口重绘invalidate、onidle

原创 2007年09月18日 16:55:00

 

一、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是否为空等。 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处理函数中使用。

二、invalidate invalidate干了两件事: (1)把某个区域加入到update region里面,当windows检测到update region不为空时,就会产生wm_paint消息. (2) 如果invalidate的第二个参数为TRUE,那么会对背景进行擦除,注意这里的擦除,应该是只是对update region区域背景的擦除. 在某个函数里面调用invalidate是把某个区域加入更新区域,同时确定是否对这些更新区域的背景擦除,然后函数返回后会调用onpaint或者ondraw函数对特定区域重绘.

三、onidle onidle系统空闲处理函数。当线程消息队列中没有需要处理的消息时,进行空闲idle处理,工具栏和状态栏更新就是运用了这个机制。在图像实时采集系统中,在高负荷速度慢的程序中,空闲机制是系统高效运行的重要保证。图像实时采集就必须不停的重绘用户窗口,如同上面所说,WM_PAINT消息只有当消息队列为空且有更新区域的时候,才会由系统发出。当消息队列为空时,应用程序立即进入空闲处理状态,此时我们在空闲处理函数中将需要更新显示的图像从图像采集多缓存中提取出来,同时invalidate窗口发出重绘消息,此时消息队列为空且有需要更新的区域,系统发出WM_PAINT消息,执行OnPaint函数,更新窗口。 空闲图像处理保证WM_PAINT消息被处理之前,更多的CPU资源消耗在图像采集与处理上。

相关文章推荐

实时波形显示---带来的VC++中窗口重绘精析(WM_PAINT)

WHAT: 实时波形显示---带来的VC中窗口重绘精析(WM_PAINT) WHY: 开发了一个小测试程序, 程序的目的是用来实时采集通道信号, 显示采集数据, 实时波形显示, 存储数据. ...

InvalidateRect只是增加重绘区域,在下次WM_PAINT的时候才生效

InvalidateRect函数中的参数TRUE表示系统会在你画之前用背景色将所选区域覆盖一次,默认背景色为白色,可以通过设置BRUSH来改变背景色。 Invalidate()之后: ...OnP...
  • liuy_yy
  • liuy_yy
  • 2012年01月10日 11:39
  • 2995

Invalidate函数及WM_PAINT总结(推荐!)

InvalidateRect只是增加重绘区域,在下次WM_PAINT的时候才生效 InvalidateRect函数中的参数TRUE表示系统会在你画之前用背景色将所选区域覆盖一次,默认背景色为白色,可...

WM_PAINT(父子窗口间)

WM_PAINT(父子窗口间) 窗口句柄(HWND)都是由操作系统内核管理的,系统内部有一个z-order序列,记录着当前从屏幕底部(假象的从屏幕到眼睛的方向),到屏幕最高层的一个窗口句柄的排序...
  • jadeshu
  • jadeshu
  • 2016年12月25日 19:30
  • 154

窗口刷新问题(WM_PAINT、BeginPaint、EndPaint的说明)

在Windows API编程中,WM_PAINT是Windows窗口的一个重要消息,应用程序就是通过响应这个消息来完成窗口的绘制。   The WM_PAINT message is generat...

窗口刷新问题(WM_PAINT、BeginPaint、EndPaint的说明

在某些情况下,显示区域的一部分被临时覆盖,Windows试图保存一个显示区域,并在以后恢复它,但这不一定能成功。在以下情况下,Windows可能发送WM_PAINT消息:  Windows擦除覆盖了部...

WM_PAINT(父子窗口间)

WM_PAINT(父子窗口间) 窗口句柄(HWND)都是由操作系统内核管理的,系统内部有一个z-order序列,记录着当前从屏幕底部(假象的从屏幕到眼睛的方向),到屏幕最高层的一个窗口句柄的排序,这...
  • dsg333
  • dsg333
  • 2013年08月17日 08:53
  • 957

窗口刷新问题(WM_PAINT、BeginPaint、EndPaint的说明)

在Windows API编程中,WM_PAINT是Windows窗口的一个重要消息,应用程序就是通过响应这个消息来完成窗口的绘制。   The WM_PAINT message is generate...

窗口刷新问题(WM_PAINT、BeginPaint、EndPaint的说明)

在某些情况下,显示区域的一部分被临时覆盖,Windows试图保存一个显示区域,并在以后恢复它,但这不一定能成功。在以下情况下,Windows可能发送WM_PAINT消息:   Windows擦除覆盖...

《JFrame类中paint()方法的重绘》

  • 2015年05月28日 01:08
  • 2KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:关于WM_PAINT,窗口重绘invalidate、onidle
举报原因:
原因补充:

(最多只允许输入30个字)