【转】关于OnPaint的工作机制
转载出处:http://blog.csdn.net/foreverhuylee/article/details/21889025
用了两年的VC++,其实对OnPaint的工作原理一直都是一知半解。这两天心血来潮,到BBS上到处发帖询问,总算搞清楚了,现在总结一下。
对于窗口程序,一般有个特点:窗口大部分的区域保持不变,只有部分区域需要重新绘制。如果将整个窗口全部刷新的话,就做了许多不必要的工作,因而,MFC采用了一套基于无效区域的处理机制。在分析无效区域处理之前,我们要明白一个现实:现在的机器还不够牛,如果够牛的话,我们干脆将整个窗口不断的重新绘制好了。事实上即使够牛也不行,对于一个单线程程序,通过一个while循环不断的刷新窗口,程序也无法相应其他消息(除非使用多线程),看来使用无效区域的处理机制还是有其必然性的。
VC++程序是基于消息机制的,你所做的任何操作,比如点击鼠标,拖动窗口,首先进入系统的消息队列。这里的系统消息队列包括多个程序的消息,系统再将消息发送给相应的程序。既然是队列,这就有一个先进先出的问题,屏幕上的无效区更新消息出现的频率就会特别高。比如当左上角更新的消息还没有处理,右下角更新的消息已经过来了。为了避免多次处理WM_PAINT消息,系统就将这些窗口更新消息合并到一条,只是将无效区范围变成包括这两次更新无效区范围在内的矩形区域。这样就减少了WM_PAINT消息的处理次数,提高了效率。
那么,在OnPaint消息处理函数中,又是怎样实现更新无效区域的呢?
首先,要明白MFC中所有绘图操作都是基于设备描述表(Device Context,简称DC)的,具体信息可参看任何一本VC++教材。DC中包含了绘图设备的各种信息,对于屏幕绘图,其实就是有一块内存(显存),专门用来存放要显示到屏幕上的信息,显示器以85HZ的频率(我以前的显示器)将其内容刷新的屏幕上。这里就到了关键点,显示器的刷新是将显存中的内容完全更新到显示器上,不存在无效区处理的问题,那么,无效区的处理一定发生在DC的绘图处理上。事实确实如此,当程序调用OnPaint消息时,首先将无效区范围传递给DC,DC在进行绘图操作时,就只更新无效区范围内的信息,其他地方的不管,这就提高了效率。
开启OnPaint函数有下面三种选择:
1)、直接发送WM_PAINT消息,用PostMessage(),SendMessage()函数发送WM_PAINT消息。使用以上两函数发送WM_PAINT消息,能将WM_PAINT消息发送到WINDOWS程序消息队列中,当WINDOWS将WM_PAINT消息发送给具体的消息处理函数时,如果窗口的无效区域为空则WINDOWS将不理睬该消息。若存在无效区域,则调用窗口处理函数处理。要注意的这里需要存在无效区域,因此要调用2)中的函数使得窗体(或者部分)无效,其处理过程与2)相同,将WM_PAINT消息送入消息处理队列。与3)不同的是WM_PAINT并不立即处理;
2)、调用相应的API实现WM_PAINT消息的发送:Invalidate(),InvalidateRect(), InvalidateRgn():以上函数将窗口的特定区域标定为无效,当WINDOWS检测到窗口中存在无效区域时将向消息队列发送WM_PAINT 消息。我当时用的就是Invalidate()函数;
3)、UpdateWindow():该函数调用后WINDOWS将向窗口发送一个非队列化的WM_PAINT消息,它不经过消息循环而直接发送给了窗口消息处理函数。如果窗口无效区域不存在,WINDOWS将不理睬该消息。注意这里因为要使得窗口无效区不存在,因此还是调用Invalidate(),InvalidateRect(), InvalidateRgn()函数,和2)中不同的是这里的WM_PAINT消息会被立即处理,而2)中是加入消息处理队列。
简单起见,你可以使用2)中方案进行问题解决。
现在你明白OnPaint的处理是怎么一回事了吧?
这里还想说一下Invalidate和UpdateWindow的区别。
Invalidate在消息队列中加入一条WM_PAINT消息,其无效区为整个客户区。而UpdateWindow直接发送一个WM_PAINT消息,其无效区范围就是消息队列中WM_PAINT消息(最多只有一条)的无效区。效果很明显,调用Invalidate之后,屏幕不一定马上更新,因为WM_PAINT消息不一定在队列头部,而调用UpdateWindow会使WM_PAINT消息马上执行的,绕过了消息队列。如果你调用Invalidate之后想马上更新屏幕,那就加上UpdateWindow()这条语句。
【转】关于OnPaint的工作机制的更多相关文章
- android 6.0 高通平台sensor 工作机制及流程(原创)
最近工作上有碰到sensor的相关问题,正好分析下其流程作个笔记. 这个笔记分三个部分: sensor硬件和驱动的工作机制 sensor 上层app如何使用 从驱动到上层app这中间的流程是如何 Se ...
- Java IO工作机制分析
Java的IO类都在java.io包下,这些类大致可分为以下4种: 基于字节操作的 I/O 接口:InputStream 和 OutputStream 基于字符操作的 I/O 接口:Writer 和 ...
- malloc 函数工作机制(转)
malloc()工作机制 malloc函数的实质体现在,它有一个将可用的内存块连接为一个长长的列表的所谓空闲链表.调用malloc函数时,它沿连接表寻找一个大到足以满足用户请求所需要的内存块.然后,将 ...
- springMVC工作机制和框架搭建配置说明
先说一下springMVC的工作机制 1.springmvc把 所有的请求都提交给DispatcherServlet,它会委托应用系统的其他模块负责对请求进行真正的处理工作. 2.Dispatcher ...
- CKPT进程工作机制
CKPT进程工作示意图 2.CKPT进程工作机制 检查点进程被触发的条件为: a> 当发生日志组切换时: b> 用户提交了事务时(commit): c> Redo log buf ...
- 15 sql base line 工作机制
<个人Configuration> 正常配置一下, 就OK了, 不用理了, oracle 11g 默认启动 发展: .从Oracle的发展角度来看,估计这种方法是Oracle发展和改进的方 ...
- HBase读写路径的工作机制
出处:http://wuyudong.com/1946.html HBase 写路径工作机制 在HBase 中无论是增加新行还是修改已有的行,其内部流程都是相同的.HBase 接到命令后存下变化信息, ...
- PHP自动加载__autoload的工作机制
PHP自动加载__autoload的工作机制 PHP的懒加载lazy loading 在 2011年11月12日 那天写的 已经有 4559 次阅读了 感谢 参考或原文 服务器君一共花费了 ...
- hadoop MapReduce 工作机制
摸索了将近一个月的hadoop , 在centos上配了一个伪分布式的环境,又折腾了一把hadoop eclipse plugin,最后终于实现了在windows上编写MapReduce程序,在cen ...
随机推荐
- 【linux】FTP添加用户,设置权限和目录
一.目的,新建一个用户 test2,登录ftp,它只有自己的主目录权限,其他同级和上级目录没有权限 二.ftp安装.配置 yum -y install vsftpd //通过yum来安装vsftpd ...
- SQL 防止注入
var strsql = "insert into Staff_Answer (ExamTitleID,QuestionsID,MultipleChoice,RightOption,Answ ...
- 如何使用T-SQL备份还原数据库及c#如何调用执行? C#中索引器的作用和实现。 jquery控制元素的隐藏和显示的几种方法。 localStorage、sessionStorage用法总结 在AspNetCore中扩展Log系列 - 介绍开源类库的使用(一) span<T>之高性能字符串操作实测
如何使用T-SQL备份还原数据库及c#如何调用执行? 准备材料:Microsoft SQL Server一部.需要还原的bak文件一只 一.备份 数据库备份语句:user master backup ...
- php简单混淆类加密文件如何解密?
最近在整理单位购买的源码时,发现源码里好多文件都混淆加密了.虽然不解密也不影响使用,但是心里总觉得有些别扭,便试着将加密的文件解密. 首先,百度了一下,看网上是否有现成的混淆类解密工具,搜到了一个ht ...
- Spring boot 配置 swagger
1.maven配置包 <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 --> <dep ...
- TextWatcher
对于一些需求,如非法字符限制(例如不允许输入#号,如果输入了#给出错误提示),做成动态判断更方便一些,而且容易扩展: 在Android里使用TextWatcher接口可以很方便的对EditText进行 ...
- 安卓编译报错:Dex Loader] Unable to execute dex: java.nio.BufferOverflowException. Check the Eclipse log for stack trace.
今天在编译别人的project时遇到了这个错误,心想应该不是代码的问题.网上搜了一下,应该是sdk版本设置的问题,要设置为最新sdk版本才可以. 解决办法就是修改project.properties里 ...
- unity, undo
如果在操作一个Object之前调用Undo.RecordObject(Object),且操作确实造成Object某些属性的改变,则会产生一个undo记录. 如果我们的架构不是直接操作Object,而是 ...
- Spring注解@ResponseBody,@RequestBody
@RequestBody 将HTTP请求正文转换为适合的HttpMessageConverter对象. @ResponseBody 将内容或对象作为 HTTP 响应正文返回,并调用适合HttpMess ...
- Android Camera API/Camera2 API 相机预览及滤镜、贴纸等处理
Android Lollipop 添加了Camera2 API,并将原来的Camera API标记为废弃了.相对原来的Camera API来说.Camera2是又一次定义的相机 API,也重构了相机 ...