RedrawWindow, UpdateWindow,InvalidateRect 用法

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会自动查找是否存在无效,并重画,该矩形区域;

简单那说一下吧:
我们知道,绘制窗口的内容,通常是在 WM_PAINT 消息的处理中。这个消息会由各种各样的情况触发,例如,某个覆盖在自己之上的窗口关闭了,等等。不过,出于效率考虑,WM_PAINT 消息的产生并不意味着整个窗口都需要重新绘制,考虑刚才说的例子,原来有个窗口 B 覆盖了窗口 A 的左上角,则窗口 B 关闭后,窗口 A 就会收到一条 WM_PAINT 消息,但是需要绘制的其实只是左上角的那一部分(为了讨论简单,不考虑窗口自身的内容一直在变化的情况,如动画窗口之类的)。这里的左上角,正是一个“无效区域”。由此,我们可以解释一下 InvalidateRect 函数了,这个函数的作用非常简单,就是把某个矩形加入到窗口的无效区域列表中,告诉窗口在处理下一条 WM_PAINT 消息时,这个区域是需要重新绘制的。顺便说一下,InvalidateRect 有个兄弟函数,不止是简单地处理一个矩形,而是处理一个区域,那就是 InvalidateRgn 函数,道理是一样的。

我们还知道,在大多数情况下,WM_PAINT 消息并不是我们程序自己发出的,而是窗口管理器(也可看做就是 Windows 系统本身)发出的。不过,系统还是给了我们自己发送这个消息的途径,那就是 UpdateWindow 函数。我们常常会看到,经典的 SDK 风格的 Hello World 程序里,主窗口创建之后,会调用 ShowWindow 函数把它显示出来,跟跟着立刻有一个 UpdateWindow 的调用,就是为了主窗口显示之后能立即进行第一次刷新。不过这是在 32 位 Windows 之前的情况,现在窗口管理器已经比原来更聪明,所以 UpdateWindow 函数的作用已经相当弱化了,不再被频繁使用。当然,UpdateWindow 还会做一些自己的判断,仅当无效区域存在时才会真正发出 WM_PIANT 消息。

至于 RedrawWindow 函数,其实现非常复杂,不过我们可以不去理会无关宏旨的部分。大概说来,如果你了解 PostMessage 和 SendMessage 的区别,那就会比较好理解。一般的 WM_PAINT 消息都是被投递到了消息队列里,等待 GetMessage 将之取出后进行处理。而 RedrawWindow 会强行直接调用窗口的回调函数就地处理。说白了,就是异步和同步的区别。这个函数允许指定要重绘的部分(矩形或者区域),因此,也常被人说这个函数兼具前面两个函数的功效。

InvalidateRect是把某个区域标记为无效,之后系统会不断向窗口Post WM_PAINT消息,直到该区域被标记为有效为止。
UpdateWindow是立即响应WM_PAINT消息,相当于直接调用窗口函数。
RedrawWindow相当于把前两者组合起来,并有很多参数可供选择,可以更灵活地进行重绘。

RedrawWindow, UpdateWindow,InvalidateRect 用法相关推荐

  1. 窗口刷新 Invalidate UpdateWindow RedrawWindow

    窗口刷新的几个函数:InvalidateUpdateWindowRedrawWindow 一:什么时候才会发生重绘窗口的消息?        当需要更新或重新绘制窗口的外观时,应用程序就会发送WM_P ...

  2. 如何设置窗口立即刷新显示

    一.引言 遇到一个问题: 清理缓存的时候,当缓存大于200M的时候,用户退出程序会显示一个对话框,这个对话框会提示用户清理缓存,当用户点击了"清理"按钮的时候,则会隐藏按钮并且提示 ...

  3. 控件重叠 关于WS_CLIPCHILDREN和WS_CLIPSIBLINGS的理解(个人认为还是相当全面的)

    WS_CLIPCHILDREN样式从字面上可以理解成ClipChildren,裁减子窗口. MSDN里的E文解释:Excludes the area occupied by child windows ...

  4. InvalidateRect()、UpdateWindow()、RedrawWindow()区别

    先看一段移动图片的程序: 绘图工作都在ReDraw()中 响应MouseMove  改变图片的位置,鼠标移动后需要重绘窗口 实验一: ReDraw()在MouseMove函数中调用 [html] vi ...

  5. 【转】VC窗口刷新InvalidateRect和UpdateWindow RedrawWindow

    首先说说WM_PAINT 这个重要的消息: The WM_PAINT message is generated by the system and should not be sent by an a ...

  6. VC++ 关于窗口刷新的几个函数InvalidateRect、UpdateWindow、RedrawWindow

    在前面写了那么多自绘控件,有必要对这几个接口做下声明解释: 这几个接口都是对执行窗体重绘的消息,那么什么时候才会发生重绘窗口的消息?答案是:当窗体需要更新内容或是重绘外观背景的时候,应用程序通常会发送 ...

  7. Invalidate()、InvalidateRect()、InvalidateRgn、UpdateWindow()

    1.Invalidate()使整个客户区无效,客户区无效则会发送WM_PAINT消息对整个客户区进行重绘.如果消息队列非空则Invalidate()不会立即重绘窗口,直到消息队列为空才向窗口发送WM_ ...

  8. InvalidateRect()与Invalidate()的用法(转)

    本文转载之:http://blog.sina.com.cn/s/blog_63393f440100nddq.html, 在此特感谢原作则的辛苦总结,非常好,转载此处,以便查阅. BOOL Invali ...

  9. VC窗口刷新InvalidateRect和…

    学习了 原文地址:VC窗口刷新InvalidateRect和UpdateWindow 作者:玩世不恭 首先说说WM_PAINT这个重要的消息: The WM_PAINT message is gene ...

最新文章

  1. 元宇宙和我有什么关系?
  2. 2021-01-05 Halcon初学者知识【7】 最简单的测距问题-点与点测距
  3. vc 中对对话框的几种操作
  4. 栈的应用-四则运算表达式
  5. 在Eclipse里搭建Scala开发环境
  6. 电气自动化c语言用什么软件,电气自动化需要哪些高级语言?
  7. 【报告分享】2021年双11电商营销全景洞察.pdf(附下载链接)
  8. 从零学ELK系列(六):Docker安装Logstash(超详细图文教程)
  9. 《『若水新闻』客户端开发教程》——10.代码编写(2)
  10. html5各种页面切换效果和模态对话框
  11. 七、K8s volume相关操作
  12. 【GD32F303开发之串口通信】
  13. thinkpad e480安装win7
  14. 桌面快捷方式图标不能删除的原因以及处理方法
  15. 机器人阿莫西_HELLO!阿莫西 本田机器人ASIMO
  16. 如何将分表汇总到总表_EXCEL如何将分表中的数据汇总到总表 - 卡饭网
  17. Could not locate executable null\bin\winutils.exe in the Hadoop binaries解决方式
  18. 红孩儿编辑器的模块设计10
  19. 计算机王道PDF408
  20. Mac修改iPhone备份到移动硬盘或其他位置,避免备份空间不足

热门文章

  1. RedisRDB持久化机制
  2. 由控制台输入年龄-不同类型不能直接比较
  3. 适合oracle运行的软件环境,创建最适合的Oracle运行环境
  4. c语言 错误 无效的控制谓词,PAT 1025反转链表的代码实现及错误分析(C语言)
  5. python集合属性方法运算_python对象及运算 序列小结 集合
  6. mysql linux-syn25000是什么_当MySQL数据库遇到Syn Flooding
  7. 在 C/C++ 中使用 TensorFlow 预训练好的模型—— 直接调用 C++ 接口实现
  8. 【Linux笔记】第七篇、配置MariaDB的字符集
  9. WD强势出击 推出全球业界首款2TB硬盘
  10. ubuntu配置vnc访问