终于懂了:WM_PAINT 与 WM_ERASEBKGND(三种情况:用户操作,UpdateWindow,InvalidateRect产生的效果并不相同),并且用Delphi代码验证 good
一直对这两个消息的关系不是太了解,借重新深刻学习windows编程的机会研究一番。
1)当窗口从无效变为有效时,比方将部分覆盖的窗口恢复时会重绘窗口时:程序首先会通过发送其他消息调用DefWindowProc,它内部会发送WM_ERASEBKGND消息,然后才会发送WM_PAINT消息,而且不经过消息队列(笔记:这结论从而何来?)。用Delphi的代码当场验证:
procedure TWinControl.WMSize(var Message: TWMSize);
begin
UpdateBounds; // 类函数
inherited;
Realign; // 类函数
if not (csLoading in ComponentState) then Resize; // 类函数,简单调用程序员事件
end; procedure TWinControl.WMMove(var Message: TWMMove);
begin
inherited;
UpdateBounds;
end;
果然发现两个inherited,会把WM_SIZE和WM_MOVE消息发送到DefWindowProc,从而触发WM_ERASEBKGND。
2)诸如UpdateWindow也会先调用WM_ERASEBKGND消息的处理过程,然后才会调用WM_PAINT消息的处理过程。
procedure TControl.Update;
begin
if Parent <> nil then Parent.Update;
end; procedure TControl.Repaint;
var
DC: HDC;
begin
if (Visible or (csDesigning in ComponentState) and
not (csNoDesignVisible in ControlStyle)) and (Parent <> nil) and
Parent.HandleAllocated then
if csOpaque in ControlStyle then
begin
DC := GetDC(Parent.Handle);
try
IntersectClipRect(DC, Left, Top, Left + Width, Top + Height);
Parent.PaintControls(DC, Self);
finally
ReleaseDC(Parent.Handle, DC);
end;
end else
begin
Invalidate;
Update;
end;
end; procedure TWinControl.Update;
begin
if HandleAllocated then UpdateWindow(FHandle); // API,只有这一处使用这个API函数,但是有另外三处会来调用当前函数,因为这有这个API函数可以真正做到立刻刷新
end; procedure TWinControl.Repaint;
begin
Invalidate;
Update;
end;
3)当调用InvalidateRect时(三个参数:hWnd,RECT,bErase),如果bErase参数为TRUE时会先调用WM_ERASEBKGND消息的处理过程。为False时,只会发送WM_PAINT消息到队列。所以InvalidateRect不是立刻调用WM_PAINT消息的处理过程,他只是给程序窗口增加一个更新区域(参阅MSDN)。
Delphi里一共有三处调用这个API函数:
procedure TControl.InvalidateControl(IsVisible, IsOpaque: Boolean);
var
Rect: TRect;
begin
if (IsVisible or (csDesigning in ComponentState) and
not (csNoDesignVisible in ControlStyle)) and (Parent <> nil) and
Parent.HandleAllocated then
begin
Rect := BoundsRect;
InvalidateRect(Parent.Handle, @Rect, not (IsOpaque or // 注意,处理的是父窗口的句柄
(csOpaque in Parent.ControlStyle) or BackgroundClipped));
end;
end; procedure TWinControl.CMInvalidate(var Message: TMessage);
var
I: Integer;
begin
if HandleAllocated then
begin
if Parent <> nil then Parent.Perform(CM_INVALIDATE, , );
if Message.WParam = then
begin
InvalidateRect(FHandle, nil, not (csOpaque in ControlStyle)); // 注意,处理的是自己的句柄,nil表示自己的整个客户区都重绘
{ Invalidate child windows which use the parentbackground when themed }
if ThemeServices.ThemesEnabled then
for I := to ControlCount - do
if csParentBackground in Controls[I].ControlStyle then
Controls[I].Invalidate;
end;
end;
end; procedure TWinControl.InvalidateFrame;
var
R: TRect;
begin
R := BoundsRect;
InflateRect(R, , );
InvalidateRect(Parent.FHandle, @R, True); // 也是重绘自己,但却是无条件重绘,而不需要考虑是否透明之类的问题,因为设计期也要绘制边框。其次,边框绘制出来以后,其内容可以被覆盖,因此不用管内容是否需要使用Theme
end;
另外关于WM_ERASEBKGND处理函数的返回值,如果处理WM_ERASEBKGND消息时返回FALSE,BeginPaint标记pt.fErase为TRUE, 如果处理WM_ERASEBKGND时返回TRUE,BeginPaint标记pt.fErase为FALSE。注意,Delphi就是这样做的,意思就是Delphi已经处理过了,不需要进一步处理。看这里:
procedure TWinControl.WMEraseBkgnd(var Message: TWMEraseBkgnd);
begin
with ThemeServices do
if ThemesEnabled and Assigned(Parent) and (csParentBackground in FControlStyle) then
begin
{ Get the parent to draw its background into the control's background. }
DrawParentBackground(Handle, Message.DC, nil, False);
end
else
begin
{ Only erase background if we're not doublebuffering or painting to memory. }
if not FDoubleBuffered or
(TMessage(Message).wParam = TMessage(Message).lParam) then
FillRect(Message.DC, ClientRect, FBrush.Handle);
end; Message.Result := ; // 表示已经处理过了
end;
如果pt.fErase标记为TRUE,指示应用程序应该处理背景,但是应用程序不一定需要处理,pt.fErase只是作为一个标记(笔记:留给程序员的灵活性依然很强)。
http://www.aichengxu.com/view/2426114
终于懂了:WM_PAINT 与 WM_ERASEBKGND(三种情况:用户操作,UpdateWindow,InvalidateRect产生的效果并不相同),并且用Delphi代码验证 good的更多相关文章
- Spring如何使用JdbcTemplate调用存储过程的三种情况
注:原文 <Spring如何使用JdbcTemplate调用存储过程的三种情况 > Spring的SimpleJdbcTemplate将存储过程的调用进行了良好的封装,下面列出使用Jdbc ...
- Tomcat内存溢出的三种情况及解决办法分析
Tomcat内存溢出的原因 在生产环境中tomcat内存设置不好很容易出现内存溢出.造成内存溢出是不一样的,当然处理方式也不一样. 这里根据平时遇到的情况和相关资料进行一个总结.常见的一般会有下面三种 ...
- TI C66x DSP 系统events及其应用 - 5.10(创建ISR的三种情况)
ISFP是服务中断的指令包,创建ISR的三种情况: 1.一个ISFP包的8条指令就能够满足ISR watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWl5ZW ...
- SSO单点登录三种情况的实现方式详解
单点登录(SSO——Single Sign On)对于我们来说已经不陌生了.对于大型系统来说使用单点登录可以减少用户很多的麻烦.就拿百度来说吧,百度下面有很多的子系统——百度经验.百度知道.百度文库等 ...
- .net webapi 接收 xml 格式数据的三种情况
webapi 接收 xml 的三种方法 前段时间接到一个任务写一个小接口,要接收java端返回过来的短信xml数据. 刚拿到项目,我的第一想法是对方会以什么形式发送xml格式的数据给我呢,设想三种情况 ...
- DG备库,实时应用如何判断,MR进程,及MRP应用归档,三种情况的查询及验证
本篇文档学习,DG备库,实时应用如何判断,MR进程,及MRP应用归档,三种情况的查询及验证 1.取消MRP进程 备库查询进程状态select process,client_process,sequen ...
- 对象的notify方法的含义和对象锁释放的三种情况
1,notify的含义 (1)notify一次只随机通知一个线程进行唤醒 (2)在执行了notify方法之后,当前线程不会马上释放该对象锁,呈wait状态的线程也不能马上获得该对象锁, 要等到 ...
- SSO单点登录三种情况的实现方式详解(转载)
单点登录(SSO——Single Sign On)对于我们来说已经不陌生了.对于大型系统来说使用单点登录可以减少用户很多的麻烦.就拿百度来说吧,百度下面有很多的子系统——百度经验.百度知道.百度文库等 ...
- Java实现PV操作 | 读者与写者(在三种情况下进行讨论)
注 :本文应结合[天勤笔记]进行学习. 1.读者优先 设置rmutex信号量来对readcount变量进行互斥访问.mutex信号量对写者与读者进行同步. static syn rmutex=new ...
- js中的数据类型隐式转换的三种情况
js的数据类型隐式转换主要分为三种情况: 1. 转换为boolean类型 2. 转换为number类型 3. 转换为string类型 转换为boolean类型 数据在 逻辑判断 和 逻辑运算 之中会隐 ...
随机推荐
- HDU 3068 最长回文 【最长回文子串】
和上一题一样,不过这题只是要求最长回文子串的长度 在此采用了非常好用的Manacher算法 据说还是O(n) 的效率QAQ 详细用法参考了上篇博客的参考资料,这两天有空学习一下~ Source cod ...
- CPU满格的元凶,这回是由于QTimer引起的(默认interval是0,太猛)
timer_space = new QTimer(); qDebug() << SystemGlobal::m_app->SpaceUse; qDebug() << ti ...
- springMVC中得到request对象,session对象
RequestAttributes ra = RequestContextHolder.getRequestAttributes(); HttpServletRequest request = ((S ...
- 第2次增加ssh 主机信任脚本
dr-mysql01:/root# cat a1.sh #用户名 uname="$1" #密码 passwd="$2" #执行检测并安装expect模块 ep= ...
- 一步一步重写 CodeIgniter 框架 (10) —— 使用 CodeIgniter 类库(续)
上一节简单实现了 CI 的类库扩展模型,所以 _ci_load_class 和 _ci_init_class 写的不是很完备.根据上节课的分析,当 system/libraries 目录下存在 Ema ...
- aliyun 主机Nginx 上配置Drupal 伪静态
网上找了好久没有正确的,后面直接在http://wiki.nginx.org/Drupal 上找到原文.但原文中复制过来会出现个 'root' rewrite directive is duplica ...
- inheritAll 及 ant antfile案例分析
<?xml version="1.0"?> <project name="a" default="targeta"> ...
- 一天一个类,一点也不累之HashSet
最近忙着一个小项目结题,故没能按时完成[一天一个类,一点也不累],还好项目优秀,算是对自己一点点的安慰和鼓励.~~~ 今天要说的是HashSet 既然是继承自Set,那么就必须有Set的一些属性,比如 ...
- Cloud Engine
Cloud Engine:大杀器如何炼成 郑昀 创建于2016/6/18 最后更新于2016/6/19 点击查看我的<如何从零搭建一个技术平台>,这是一个系列.转载时请注明“转载自旁观 ...
- Android_简单笔记一
入门学习Android的简单笔记(已经安装好了开发环境ADT) 一.关于 AndroidManifest.xml文件 1. android:icon和android:label定义了应用程序安装后显示 ...