WM_PAINT在微软官方定义中,wParam和lParam都没有使用,所以就被Delphi给重定义了这个消息,还增加了DC(Delphi可任意改写消息的结构)
LRESULT CALLBACK WindowProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
);
Parameters
- wParam
-
This parameter is not used.
- lParam
-
This parameter is not used.
Delphi里去掉句柄之后重定义:
TWMPaint = packed record
Msg: Cardinal;
DC: HDC;
Unused: Longint;
Result: Longint;
end;
经过测试,其大小为16:
procedure TForm1.Button3Click(Sender: TObject);
begin
ShowMessage(IntToStr(sizeof(TWMPaint)));
end;
重定义之后的利用过程,看这里:
procedure TWinControl.WMPaint(var Message: TWMPaint);
var
DC, MemDC: HDC;
MemBitmap, OldBitmap: HBITMAP;
PS: TPaintStruct;
begin
if not FDoubleBuffered or (Message.DC <> ) then // 消息里已经自带DC,用这个绘制就可以了
begin
if not (csCustomPaint in ControlState) and (ControlCount = ) then // 针对Windows自带控件,其包含的子控件数量为0,且没有自绘标记。
inherited // 走向1,主要是针对Windows系统原生控件,微软定义的基本控件,总不会有错,应该内含BeginPaint了吧?
else
PaintHandler(Message); // 走向2,主要是针对Delphi的自绘控件,内含BeginPaint
end
else
begin
DC := GetDC(); // 走向3,消息里没有自带DC,那么就现取,内含BeginPaint
MemBitmap := CreateCompatibleBitmap(DC, ClientRect.Right, ClientRect.Bottom);
ReleaseDC(, DC);
MemDC := CreateCompatibleDC();
OldBitmap := SelectObject(MemDC, MemBitmap);
try
DC := BeginPaint(Handle, PS);
Perform(WM_ERASEBKGND, MemDC, MemDC);
Message.DC := MemDC; // 其实这有这里进行赋值
WMPaint(Message); // 中间有了DC,赶紧使用
Message.DC := 0;
BitBlt(DC, , , ClientRect.Right, ClientRect.Bottom, MemDC, , , SRCCOPY);
EndPaint(Handle, PS);
finally
SelectObject(MemDC, OldBitmap);
DeleteDC(MemDC);
DeleteObject(MemBitmap);
end;
end;
end;
继续传递:
procedure TWinControl.PaintHandler(var Message: TWMPaint);
var
I, Clip, SaveIndex: Integer;
DC: HDC;
PS: TPaintStruct;
begin
DC := Message.DC; // 使用消息带来的句柄(没准在别处赋值的),比如子控件挨个向父控件发送重绘请求,这样就不用每次都重新给DC赋值了。但是这里不是引用,出了这个函数,Message.DC的值并没有被改变。fixme 还是没全懂
if DC = then DC := BeginPaint(Handle, PS); // 如果DC是空的,就要取得它(如果是单独的控件,肯定要执行)
try
if FControls = nil then PaintWindow(DC) else
begin
SaveIndex := SaveDC(DC);
Clip := SimpleRegion;
for I := to FControls.Count - do
with TControl(FControls[I]) do
if (Visible or (csDesigning in ComponentState) and
not (csNoDesignVisible in ControlStyle)) and
(csOpaque in ControlStyle) then
begin
Clip := ExcludeClipRect(DC, Left, Top, Left + Width, Top + Height);
if Clip = NullRegion then Break;
end;
if Clip <> NullRegion then PaintWindow(DC);
RestoreDC(DC, SaveIndex);
end;
PaintControls(DC, nil); // 还要把自己的DC带给子控件
finally
if Message.DC = then EndPaint(Handle, PS);
end;
end; procedure TGraphicControl.WMPaint(var Message: TWMPaint);
begin
if Message.DC <> then // 注意,如果DC为零,根本就不自绘(没法自绘)
begin
Canvas.Lock;
try
Canvas.Handle := Message.DC; // 可见的本质上,DC就是一个控件的Canvas句柄,而且是父控件的DC句柄
try
Paint;
finally
Canvas.Handle := 0;
end;
finally
Canvas.Unlock;
end;
end;
end; procedure TCustomControl.WMPaint(var Message: TWMPaint);
begin
Include(FControlState, csCustomPaint);
inherited;
Exclude(FControlState, csCustomPaint);
end; procedure TWinControl.WMPrintClient(var Message: TWMPrintClient);
begin
with Message do
if Result <> then
if ((Flags and PRF_CHECKVISIBLE) = ) or Visible then
PaintHandler(TWMPaint(Message))
else
inherited
else
inherited;
end;
回头做个实验,一个TWinControl包含多个TCustomControl子控件。WM_PAINT第一次会发给父控件,然后依次重绘TCustomControl子控件,但是每个TCustomControl子控件都会通过inherited把消息传回来,当第一次传回来的时候,这个消息的DC就应该不是0了。
WM_PAINT在微软官方定义中,wParam和lParam都没有使用,所以就被Delphi给重定义了这个消息,还增加了DC(Delphi可任意改写消息的结构)的更多相关文章
- 自定义消息中如果需要定义WPARAM和LPARAM,该怎么使用和分配?
写Windows程序不可避免要使用自定义的消息,也就是从WM_USER开始定义的消息.在定义一个消息后,往往我们还要定义针对该消息的WPARAM甚至是LPARAM.WPARAM和LPARAM是什么,可 ...
- MVC4学习之官方教程中迁移版本库报错
因工作需要,学习MVC4,但是微软官方教程中迁移版本库步骤在本地测试报错 官方教程地址:http://www.asp.net/mvc/overview/older-versions/getting-s ...
- C++中重定义的问题——问题的实质是声明和定义的关系以及分离式编译的原理
这里的问题实质是我们在头文件中直接定义全局变量或者函数,却分别在主函数和对应的cpp文件中包含了两次,于是在编译的时候这个变量或者函数被定义了两次,问题就出现了,因此,我们应该形成一种编码风格,即: ...
- C++中的继承详解(3)作用域与重定义,赋值兼容规则
作用域与同名隐藏 一样的,先上代码 1 class A 2 { 3 public: 4 int a_data; 5 void a() 6 { 7 cout << "A" ...
- C++中的继承(3)作用域与重定义,赋值兼容规则
作用域与重定义(同名隐藏) 一样的,先上代码 1 class A 2 { 3 public: 4 int a_data; 5 void a() 6 { 7 cout << "A& ...
- C++中的继承(3)作用域与重定义,赋值兼容规则
1.作用域与重定义(同名隐藏) 一样的,先上代码 1 class A 2 { 3 public: 4 int a_data; 5 void a() 6 { 7 cout << " ...
- LRESULT与wParam和lParam的问题
在微软vc提供的头文件中有定义在winnt.h中typedef long LONG;在windef.h中typedef LONG LRESULT; 所以LRESULT就是long,也就是长整形之所以取 ...
- wParam与lParam的区别
wParam与lParam的区别 lParam 和 wParam 是宏定义,一般在消息函数中带这两个类型的参数,通常用来存储窗口消息的参数. LRESULT CALLBACK WindowProc(H ...
- WPARAM和LPARAM的含义
lParam 和 wParam 是宏定义,一般在消息函数中带这两个类型的参数,通常用来存储窗口消息的参数. LRESULT CALLBACK WindowProc(HWND hwnd, UINT uM ...
随机推荐
- 这些屌炸天的创业者为何对投资人说NO
曾有人说,世上的创业者只分为两种,一种是找到投资的,一种是没有找到的. 但其实还有第三种,就是那些拒绝了投资人的创业者. 他们摒弃了投资人抛来的橄榄枝,并非不差钱,不接受投资的原因大体出于两个方面,一 ...
- Spring Boot 属性配置和使用(转)
Spring Boot 属性配置和使用 Spring Boot 允许通过外部配置让你在不同的环境使用同一应用程序的代码,简单说就是可以通过配置文件来注入属性或者修改默认的配置. Spring Boot ...
- Maven2的配置文件settings.xml(转)
http://maven.apache.org/settings.html简介: 概览当Maven运行过程中的各种配置,例如pom.xml,不想绑定到一个固定的project或者要分配给用户时,我们使 ...
- 「JAVA」:Berkeley DB的JAVA连接
Berkeley DB是一个嵌入式的数据库,它适合于管理海量的.简单的数据.关键字/数据(key/value)是Berkeley DB用来进行数据管理的基础.每个key/value构成了一条记录,而整 ...
- 通过加索引对sql语句优化
今天看数据库的时候遇到这样一个SQL语句: select substr(a.djxh,) as id, (a.nd || a.yf) DECL_YM, a.zspm_dm as LEVY_ITEM_I ...
- Sicily-1006
一. 题意 这道题就是考排列组合吧,再来就是比较一下字符的下标算一下两个ranking的距离.然后我总结了一个排列和一个组合的实现方法,这道题直接用的是stl 里面的next_permutation ...
- BZOJ 1631: [Usaco2007 Feb]Cow Party
题目 1631: [Usaco2007 Feb]Cow Party Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 491 Solved: 362[Sub ...
- BZOJ 1621: [Usaco2008 Open]Roads Around The Farm分岔路口
题目 1621: [Usaco2008 Open]Roads Around The Farm分岔路口 Time Limit: 5 Sec Memory Limit: 64 MB Submit: 56 ...
- java学习之观察者设计模式
package com.gh.observer; import java.util.Observable; /** * 被观察者对象 * 必须继承被观察者抽象类 * @author ganhang * ...
- Android zip文件压缩解压缩
DirTraversal.java <P style="TEXT-ALIGN: left; PADDING-BOTTOM: 0px; WIDOWS: 2; TEXT-TRANSFORM ...