写在属于自己的体会,哪怕只是一点点,也是真的懂了。否则有那么多书,如果只是不过脑子的学一遍看一遍,又有谁真的掌握了这些知识呢?

这样你或许就明白了为什么不能直接用SendMessage和PostMessage发送WM_PAINT的原因:由于没有invalidate,系统认为窗口没有更新的必要,于是就对发来的WM_PAINT消息不理不睬。解决方案就是——我们自己invalidate!相关的API就是InvalidateRect()和InvalidateRgn().

还想说一下Invalidate和UpdateWindow的区别。Invalidate在消息队列中加入一条WM_PAINT消息,其无效区为整个客户区。而UpdateWindow直接发送一个WM_PAINT消息,其无效区范围就是消息队列中WM_PAINT消息(最多只有一条)的无效区(估计把消息从消息队列中提出,直接发送给窗口,走关系户的路子)。效果很明显,调用Invalidate之后,屏幕不一定马上更新,因为WM_PAINT消息不一定在队列头部,而调用UpdateWindow会使WM_PAINT消息马上执行的,绕过了消息队列。如果你调用Invalidate之后想马上更新屏幕,那就加上UpdateWindow()这条语句

用WM_PAINT处理重画是异步(asynchronous)的。也就是说,在invalidate之后窗口并不会立即重画而是等到消息队列为空时再重画,这样就有一个时间差。这个事件差有时短到不被注意,但有时就是个大问题(尤其是当程序需要执行耗费时间的任务,如串口I/O)。这时可以采用同步重画法,直接用GetDC()获得hDC执行重画操作。如果非要使用WM_PAINT来同步重画(个人比较喜欢这种方法,和重画有关的代码就应该在WM_PAINT的处理程序里嘛),可以使用UpdateWindow()和RedrawWindow(). 这两个API函数会直接把WM_PAINT送进窗口的消息队列而不是应用程序的消息队列,这样就不用等到最后了。注意前者当update region不为空时才会发送WM_PAINT,后者的控制选项更为丰富。

RedrawWindow相当于先调用InvalidateRect,紧接着又调用UpdateWindow,此外RedrawWindow还提供了一些前两者没法做到的功能。

这个WM_PAINT消息既可能由系统发送,也可能由应用程序人工发送(比如自绘时需要)。当鼠标指向这个区域时加载hover图像以获得hottrack效果。这时操作系统自然不会认为有重画的必要,但程序却必须重画,这时就得人工发送WM_PAINT消息了。注意不要傻乎乎地直接用SendMessage或PostMessage发送WM_PAINT,后面会解释原因。重画很费时间和资源,并且也不是应用程序的“主业”,因此系统也知道要尽量减少重画的次数。系统只在应用程序的消息队列为空的时候才发送WM_PAINT,这就是为什么当程序死锁时窗口图像不会更新。同样为了减少重画的工作量,Windows提出了update region的概念。

比如原来在窗口上面的一个窗口现在挪走了,系统就把新露出来的区域定义为update region(这个过程称为invalidate)。系统不断检测一个窗口的update region是否为空,当update region不为空并且应用程序没有消息要处理(消息队列为空)的时候,系统就通过WM_PAINT告诉应用程序“现在没事干了?窗口的一部分需要重画,你把这一部分重画一下”。应用程序重画了窗口之后,把update region重新设置为空(这个过程称为validate),如此不断循环。如果消息队列不为空,系统就把update region不断更新(采用取并集的方法),等消息队列为空的时候一起处理。这就大大减少了重画的次数。

参考:

http://hi.baidu.com/pro_lily/item/a5c38afffac2495ac9f33721
http://hi.baidu.com/dongyiju2/item/3f8c2a10725e2526f7625c36

--------------------------- WM_PAINT 的产生原因 ------------------------------

当WM_PAINT不是由InvalidateRect产生时,即由最大化,最小化等产生时,或者移动产生(移动有时只会产生WM_ERASEBKGND消息)系统先发送WM_ERASEBKGND消息,再发送WM_PAINT消息.
如果处理WM_ERASEBKGND消息时返回FALSE,BeginPaint标记pt.fErase 为TRUE,如果处理WM_ERASEBKGND时返回TRUE,BeginPaint标记pt.fErase为FALSE.

当WM_PAINT由InvalidateRect产生时,先发送WM_PAINT消息(读书笔记:再看情况发送WM_ERASEBKGND)(异步),如果InvalidateRect的bErase为TRUE,BeginPaint检查到更新区域需要删除背景,向窗口发送一个WM_ERASEBKGND消息,如果处理WM_ERASEBKGND消息时返回FALSE,BeginPaint标记pt.fErase 为TRUE,如果处理WM_ERASEBKGND时返回TRUE,BeginPaint标记pt.fErase为FALSE.
如果pt.fErase标记为TRUE,指示应用程序应该处理背景,但是应用程序不一定需要处理,pt.fErase只是作为一个标记.

http://hi.baidu.com/dirtyface001/item/d6765b0d8a47338f03ce1b28
http://hi.baidu.com/qinfengxiaoyue/item/1a8f260ccbd3c528a0312d08

VC里OnPaint几点要注意的地方(没有invalidate,系统认为窗口没有更新的必要,于是就对发来的WM_PAINT消息不理不睬)的更多相关文章

  1. artTemplate里一个比不上jQuery tmpl模板的地方就是放一个数组进去它不会自动循环.

    artTemplate里一个比不上jQuery tmpl模板的地方就是放一个数组进去它不会自动循环.

  2. 终于懂了:TWinControl.DefaultHandler里的CallWindowProc(FDefWndProc)还挺有深意的,TButton对WM_PAINT消息的处理就是靠它来处理的(以前不明白为什么总是要调用inherited,其实就是没有明白TWinControl.DefaultHandler的真正用处)

    我忽然发现:TButton既没有处理WM_PAINT,又没有Paint()或者PaintWindow(),那么它是什么时候被绘制的? Form1上放2个TButton,然后设置代码: procedur ...

  3. 将VirtualBox里安装的虚拟机在后台运行方法(在状态栏隐藏窗口)

    由于工作和学习需要,经常要开一个虚拟机开测试和开发,虚拟机我选择Oracle公司的VirtualBox(用了几年了,感觉不错的一款产品),经常开着这个窗口感觉有些浪费资源,这样隐藏窗口就在需求了. 将 ...

  4. 图解在VC里使用graphics.h画图(相似TC)

    1 www.easyx.cn 下载 EasyX 库 我下的2014;解压后例如以下图: 2 依据自己的VC 版本号进行安装 3 在控制台画一个圆 #include <graphics.h> ...

  5. 文件的概念以及VC里的一些文件操作API简介

    文件的基本概念 所谓“文件”是指一组相关数据的有序集合. 这个数据集有一个名称,叫做文件名. 实际上在前面的各章中我们已经多次使用了文件,例如源程序文件.目标文件.可执行文件.库文件 (头文件)等.文 ...

  6. VC里打开网页

    转载请注明来源:https://www.cnblogs.com/hookjc/ 1     ShellExecute 开放分类: API 编程 ShellExecute函数原型及参数含义如下: She ...

  7. VC里判断系统是不是64bit

    不过,理论上来说,也可以用一个int的大小作为参考,判断是32位还是64位.sizeof(int) == 4 //32位系统.sizeof(int) == 8 //64位系统. 也可以使用函数如下: ...

  8. MySQL 遇到的问题:在服务里找不到自己的 MySQL,以及在命令行窗口中运行服务出现的问题。

    1.用数据库的时候在服务里找不到自己的 MySQL ,于是就想用命令行窗口去运行. ①.在开始里,键入 cmd ,打开命令行窗口. ②.输入:mysql -u root -p 回车,这时会提示请输入密 ...

  9. 终于懂了:WM_PAINT中应该用BeginPaint与EndPaint这两个api,它们的功能正是使无效区域恢复(所以WM_PAINT里即使什么都不做,也必须写上BeginPaint与EndPaint)——Delphi里WM_PAINT消息的三个走向都做到了这一点 good

    程序本来是想实现鼠标单击改变背景颜色.可是,程序运行时,为什么没有任何消息触发,背景颜色就一直不断的改变了?WM_PAINT怎么被触发的 #include <windows.h> #inc ...

随机推荐

  1. 洛谷——P1690 贪婪的Copy

    P1690 贪婪的Copy 题目描述 Copy从卢牛那里听说在一片叫yz的神的领域埋藏着不少宝藏,于是Copy来到了这个被划分为个区域的神地.卢牛告诉了Copy这里共有个宝藏,分别放在第Pi个(1&l ...

  2. Add and Search Word - Data structure design - LeetCode

    Design a data structure that supports the following two operations: void addWord(word) bool search(w ...

  3. UVA 11389 The Bus Driver Problem 贪心水题

    题目链接:UVA - 11389 题意描述:有n个司机,n个早班路线和n个晚班路线,给每个司机安排一个早班路线和一个晚班路线,使得每个早班路线和晚班路线只属于一个司机.如果一个司机早班和晚班总的驾驶时 ...

  4. kafka消费者客户端

    Kafka消费者 1.1 消费者与消费者组 消费者与消费者组之间的关系 ​ 每一个消费者都隶属于某一个消费者组,一个消费者组可以包含一个或多个消费者,每一条消息只会被消费者组中的某一个消费者所消费.不 ...

  5. Maven在[INFO] Generating project in Interactive mode卡住的问题解决

    我的环境: Apache Maven 3.3.9 (bb52d8502b132ec0a5a3f4c09453c07478323dc5; 2015-11-11T00:41:47+08:00) Maven ...

  6. 关于Web项目的pom文件处理

    pom文件的方式需要修改的是 <packaging>war</packaging> <profiles> <profile> <id>com ...

  7. Web终端之使用shellinabox在浏览器进行ssh登录

    shellinbox有一个内建的web server作为基本的web ssh client,允许你通过指定的端口访问linux服务器的ssh shell,只要你的浏览器支持AJAX/JS/CSS就可以 ...

  8. rsync一些常用的命令

    渗透测试的时候会遇到RSYNC 匿名访问 在对一些大型互联网进行测试的时候经常会遇到rsync. 什么是Rsync Rsync(remote synchronize)是一个远程数据同步工具,可通过LA ...

  9. python例子

    例一:for循环 for i in range(1,100): if i==23: print "great,%s you got your lucky number:" %(i) ...

  10. Vue避免 v-if 和 v-for 用在一起

    永远不要把 v-if 和 v-for 同时用在同一个元素上. 一般我们在两种常见的情况下会倾向于这样做: 为了过滤一个列表中的项目 (比如 v-for="user in users" ...