WM_PAINT产生原因有2种(用户操作和API)——WM_PAINT和WM_ERASEBKGND产生时的先后顺序不一定(四段讨论)
1. 当WM_PAINT不是由InvalidateRect产生时,即由最大化,最小化等产生时,或者移动产生(移动有时只会产生WM_ERASEBKGND消息)系统先发送WM_ERASEBKGND消息,再发送WM_PAINT消息.
如果处理WM_ERASEBKGND消息时返回FALSE,BeginPaint标记pt.fErase 为TRUE,如果处理WM_ERASEBKGND时返回TRUE,BeginPaint标记pt.fErase为FALSE.
2.当WM_PAINT由InvalidateRect产生时,先发送WM_PAINT消息(异步),如果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只是作为一个标记.
补充:DefWindowProc(hWnd, message, wParam, lParam)处理WM_ERASEBKGND消息时默认用下面的画刷清除背景
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
WM_ERASEBKGND返回TRUE和返回FALSE是一个规范,一般情况下没有什么区别,但是如果什么时候用到了,会根据函数返回值判断后续处理。因此最好按照要求返回数据.
http://note.sdo.com/u/432181446/NoteContent/pMF36~jDXzSFnM1rg001sf
------------------------------------------------------------------------------------------
当WM_PAINT不是由InvalidateRect产生时,即由最大化,最小化等产生时,或者移动产生(移动有时只会产生WM_ERASEBKGND消息)系统先发送WM_ERASEBKGND消息,再发送WM_PAINT消息.
当WM_PAINT由InvalidateRect产生时,先发送WM_PAINT消息,OnPaint()这个执行内部向窗口发送了 WM_ERASEBKGND消息来刷新背景。在OnPaint()函数中会首先调用BeginPaint()函数,在BeginPaint 函数中会发送WM_ERASBKGND.
OnEraseBkgnd函数内部不要使用 UpdateWindow MoveWindow SetWindowPos RedrawWindow等引起调用wm_paint的函数,如果在 OnEraseBkgnd 函数处理过程中 产生了需要刷新的无效区,导致系统产生wm_paint消息,这样就产生了死循环!
要在程序中想要把背景色设置成其他颜色(不是默认的),那这个代码一般在WM_ERASEBKGND 的消息响应函数中执行,而当我们想在界面上画个图形之类的,一般在WM_PAINT的消息响应函数如OnPain中执行。凡事无绝对,就是你也可以把 背景的设置放在OnPain中绘制
WM_ERASEBKGND如果返回非0,说明已经重画背景,如果返回0,程序将继续试图重画背景。
问题:Windows系统没有发出WM_ERASEBKGND消息
根据MSDN的描述,当windows被最小化时,系统需要绘制icon。
通常,系统会首先发送WM_ICONERASEBKGND给窗口,然后再发送WM_PAINTICON消息给窗口。MSDN又说,如果应用程序的WNDCLASS结构的hIcon成员如果为NULL,那么系统会发送WM_ERASEBKGND消息来替代
WM_ICONERASEBKGND消息,然后再发送WM_PAINT消息。为此应用程序应该在自己的代码中,
通过IsIconic()函数来判断当前是否application处于miminized状态。如果是,那么在
其OnEraseBkGnd函数和OnPain函数中都应该根据其minimized状态来绘制图标背景和图标。当然,MFC程序会封装WNDCLASS结构,为此我们看不到RegisterClass函数。为此我通过
GetClassInfo函数来获取WNDCLASS结构,结果发现hIcon域为NULL。根据MSDN的描述,在窗口minimized的情况下,系统应该会发出WM_ERASEBKGND消息,但是我通过
打印TRACE信息发现,系统根本没有在minimized情况下发出WM_ERASEBKGND消息。另外,根据MSDN的描述,WM_ICONERASEBKGND消息仅仅在Windows NT 3.51 and earlier有效。请高手指点,谢谢!!
The WM_ERASEBKGND message is sent when the window background must be erased (for example, when a window is resized). The message is sent to prepare an invalidated portion of a window for painting.
-------------
个人觉得最小化(IsIconic函数调用为TRUE),图标化了,就没有必要发送WM_ERASEBKBND消息来绘制窗口背景,可能是为了效率。
刚刚搜索到一个老外的描述:他说IsIconic是win16和NT3.x以前的东西,现在已经可以不需要这个分支了。另外,在百度上看到这篇文章:觉得分析得有道理。当窗口最小化时,此时已经不需要绘制client area,为此不会发出WM_PAINT消息。实际上,仅仅当application client area有update region时,系统才会在message queue为空时,才会发出WM_PAINT消息。而当application接收到WM_PAINT消息时,会首先调用BeginPaint函数来准备display device context(在CDialog::OnPaint => CPaintDC dc(this)构造函数之中),如果update region被标记为erasing,那么BeginPaint又会发出WM_ERASEBKGND消息。为此,既然在最小化时系统没有发送WM_PAINT消息给窗口,为此更不会发出WM_ERASEBKGND消息。
我曾在最小化时,故意发出WM_PAINT消息,此时该消息会进入到OnPaint的IsIconic分支。但是,如果你故意发出WM_ERASEBKGND消息,那么该消息必须在Cdialog::OnSysCommand函数之前,否则会被系统丢弃,为此不会进入OnEraseBkGnd函数。
谢谢VisualEleven的回复,系统确实为了优化client area operation而限制了某些不必要消息的发送。
http://www.debugease.com/vc/1246693.html
请问MFC的一个代码简单却功能奇怪的问题?
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
上面这个代码是MCF向导自动生成的,我跟踪了一下在最小化,最大化的过程发现没有被执行到,去掉 发现出也没出现什么不同,为何MFC要默认的帮我们生产上面的代码,有哪位高手知道上面的代码正真的目的是什么?在什么情况下会被执行到?
这段代码是有用的,尽管通常情况下不会被调用。他的作用是在最小化状态下重绘窗口图标。
IsIconic()作用是判断窗口是否处于最小化状态(点击了最小化按钮之后)。
对于普通的对话框来说,如果你在if (IsIconic()) 下面加入AfxMessageBox("haha") ,你会发现消息框并不会弹出。
原因是,if (IsIconic()) 这段代码是在OnPaint()函数内,当你最小化了对话框之后,虽然IsIconic()的值是TRUE,但是OnPaint()函数并不会运行。因为OnPaint()响应的是WM_PAINT消息,而WM_PAINT消息是针对客户区的。一个最小化了的窗口不需要重绘客户区。
为了验证这一点,可以设置一定时器,在OnTimer()函数里写上
if(IsIconic()) MessageBeep(MB_OK);
当你点击最小化按钮后,你会听见嘟嘟声。
那么这段代码究竟有什么用?它是不是永远不会被执行呢?当然不是。举两个例子。
第一,如果你强行发送WM_PAINT消息,它会执行。
第二,特殊的对话框。比如一个ToolBox风格的对话框。这个对话框不显示在任务栏,在最小化之后它会变成一个很小的一条显示在桌面上。这时如果它被遮挡,就会出发WM_PAINT消息,从而执行那段代码。
总之,一般情况下可以不要这段代码,它的特殊用途我也不是很了解,但是我们至少可以知道它是怎么样工作的。
http://zhidao.baidu.com/question/50297340
WM_PAINT产生原因有2种(用户操作和API)——WM_PAINT和WM_ERASEBKGND产生时的先后顺序不一定(四段讨论)的更多相关文章
- WM_PAINT与WM_ERASEBKGND(用户操作和API这两种情况产生消息的顺序有所不同)
1)当WM_PAINT不是由InvalidateRect产生时,即由最大化,最小化等产生时,或者移动产生(移动有时只会产生WM_ERASEBKGND消息)系统先发送WM_ERASEBKGND消息,再发 ...
- 终于懂了:WM_PAINT 与 WM_ERASEBKGND(三种情况:用户操作,UpdateWindow,InvalidateRect产生的效果并不相同),并且用Delphi代码验证 good
一直对这两个消息的关系不是太了解,借重新深刻学习windows编程的机会研究一番. 1)当窗口从无效变为有效时,比方将部分覆盖的窗口恢复时会重绘窗口时:程序首先会通过发送其他消息调用DefWindow ...
- Entity Framework 实体框架的形成之旅--几种数据库操作的代码介绍(9)
本篇主要对常规数据操作的处理和实体框架的处理代码进行对比,以便更容易学习理解实体框架里面,对各种数据库处理技巧,本篇介绍几种数据库操作的代码,包括写入中间表操作.联合中间表获取对象集合.递归操作.设置 ...
- jQuery中模拟用户操作
有时为了节省不想手动操作网页,但又想看到用户操作时的效果,可以用到jQuery提供的trigger方法.见下图代码 在不点击按钮时仍然想弹出this.value 我们只需要在后面加上.trigger( ...
- 关于Linux 交互(用户操作接口)
Linux 系统提供两种基本接口给用户操作:命令行,图形界面. 不同接口也有相应的访问终端. 一.命令行 Command Line Linux系统命令行,一般指 Shell. Shell 接受经键盘输 ...
- 从知乎首页用户操作入口学习到的CSS技巧 - 合理利用伪元素实现一些装饰样式
最近在模仿做一个静态的PC版知乎,在模仿的过程中,从知乎工程师的方法中学到了不少知识,比如CSS方面的,以下介绍一个今天学到的伪元素的技巧. 示例 DOM结构为: <div class=&quo ...
- Linux下ftp安装配置及三种用户的验证
一.原理简介 二.安装配置 三.三种用户的验证 一.简介 FTP即文件传输协议(File Transfer Protocol),完成各主机的文件共享功能,基于客户端-服务器的协议,工作在应用层,tcp ...
- C#路径的八种相关操作,判断字符串是否为路径等
原文:C#路径的八种相关操作,判断字符串是否为路径等 1.判定一个给定的C#路径是否有效,合法 通过Path.GetInvalidPathChars或Path.GetInvalidFileNameCh ...
- linux下用户操作记录审计环境的部署记录
通常,我们运维管理人员需要知道一台服务器上有哪些用户登录过,在服务器上执行了哪些命令,干了哪些事情,这就要求记录服务器上所用登录用户的操作信息,这对于安全维护来说很有必要.废话不多说了,下面直接记录做 ...
随机推荐
- mysql如何开启远程连接
链接地址:http://jingyan.baidu.com/article/046a7b3ed85f3ef9c27fa9dc.html 大家在公司工作中,经常会遇到mysql数据库存储于某个人的电脑上 ...
- C-KMP
一.BF算法 --传统算法 BF算法是普通的模式匹配算法,BF算法的思想就是将目标串S的第一个字符与模式串P的第一个字符进行匹配,若相等,则继续比较S的第二个字符和P的第二个字符:若不相等,则比较S的 ...
- KestrelServer
KestrelServer 跨平台是ASP.NET Core一个显著的特性,而KestrelServer是目前微软推出了唯一一个能够真正跨平台的Server.KestrelServer利用一个名为Ke ...
- CSharp Algorithm - Replace multiplication operator with a method
/* Author: Jiangong SUN */ How to replace multiplication operation with a method? For example, you h ...
- 给你的Cordova HybridApp加入Splash启动页面
如今最新的Cordova 3以上的版本号支持启动画面了,是通过cordova插件实现的. 眼下Splash插件支持android,ios,blackberry等多个平台. 加入插件等步骤例如以下: 加 ...
- Python文件处理(1)
读取文件 解决方案: 最简单的就是一次性读取所有的内容放在一个大字符串中 all_the_text=open('thefile.txt').read() all_the_data=open('abin ...
- Android 系统api实现定位及使用百度提供的api来实现定位
目前在国内使用定位的方法主要是 1. Android系统提供的 LocationManager locationManager = (LocationManager) getSystemService ...
- Server Tomcat v7.0 Server at localhost was unable
在eclipse启动tomcat时遇到超时45秒的问题: Server Tomcat v7.0 Server at localhost was unable to start within 45 se ...
- SQL注入(一)普通型注入
既然说了从头开始,先从注入开始吧,先来温习一下之前会的一些注入. PHP注入 0x01: 判断是否存在注入: ' 报错 ' and 1=1 正确 ' and 1=2 错误 0x01: or ...
- Oracle Patch Bundle Update
一.相关知识介绍 以前只知道有CPU(Critical Patch Update)和PSU(Patch Set Update),不知道还有个Bundle Patch,由于出现了TNS-12531的BU ...