首页 > 代码库 > TGraphicControl和TCustomControl自绘过程
TGraphicControl和TCustomControl自绘过程
TGraphicControl = class(TControl) // 这个类实在是简单,因为所有事情都已经委托给它的父Win控件了,只要管自己即可
private
FCanvas: TCanvas; // 私有内部画板,不用程序员申请就有了
// 注意区别,其实图形控件没有画自己控件一说(但仍然接受WM_PAINT消息),直接响应消息并绘画即可。
// 其父类已经在VCL体系中搭好了框架绘制当前图形控件,它会调用Paint;函数执行程序员的画图动作。
// Graphic控件自绘过程:
// 0. Windows发消息给其父Win控件
// 1. 如果父控件是WinControl,那么流程是:WMPaint, PaintHandler, PaintWindow, PaintWindows 绘制所有图形子控件
// 2. PaintWindows 给所有图形子控件执行 Perform(WM_PAINT, DC, 0) 消息,其中DC是父控件的句柄
// 3. 图形控件响应WM_PAINT消息对应的WMPaint函数,程序员不必改动这个函数,
// 4. WMPaint函数调用虚函数Paint,程序员改写Paint可被准确应用上而不必对整个VCL框架有任何改动,甚至不用理解这件事情,只需填写Paint函数即可
// 5. 如果父控件是CustomControl,那么会再多绕一道弯:先执行CustomControl的WMPaint,目的是加上自绘状态,再调用WinControl的WMPaint
procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
protected
procedure Paint; virtual; // 空函数
property Canvas: TCanvas read FCanvas;
public
constructor Create(AOwner: TComponent); override; // 简单创建Canvas并连接当前图形控件
destructor Destroy; override;
end;
TCustomControl = class(TWinControl) // 这个类的主要框架都在TWinControl里搭好了框架,所以才会出现最简单的三明治风格
private
FCanvas: TCanvas; // 私有内部画板,不用程序员申请就有了
// Custom控件自绘过程:
// 0. Windows发消息给CustomControl自己
// 1. 响应绘制自己控件的源头,还是从CustomControl控件(也是Win控件,具有句柄)的WMPaint函数开始。
// 2. 三明治风格,加上自绘风格后,调用父类同名WMPaint函数,这样可以把自己和所有子控件都管起来(VCL框架预先准备)
// 3. 父类同名函数根据四种不同情况:双缓冲,DC句柄,子控件数量,自绘标记,作出不同的判断进行绘制
// 4. 先绘制自己,再绘制所有子图形控件
// 5. 绘制自己的时候,父类的管理函数(一般是PaintHandler)会调用本类的PaintWindow覆盖函数(虚函数)
// PaintWindow又会调用Paint函数,程序员通过改写Paint函数的内容,达到在框架内被自动调用的目的
// 6. 图形子控件的绘制过程通过父控件发送WM_PAINT消息,它包含了父控件的DC句柄,然后委托给图形子控件自己进行绘制
// 道理非常类似,只是少绕一些弯子,WMPaint直接调用本类的Paint函数,而程序员通过改写Paint函数的内容,达到在框架内被自动调用的目的
procedure WMPaint(var Message: TWMPaint); message WM_PAINT; // 加Custom风格后重绘,调用TWinControl.WMPaint函数,因为要重画所有子控件
protected
// 此函数只被PaintHandler调用,后者又会被WMPaint WMPrintClient调用
procedure PaintWindow(DC: HDC); override; // 虚函数,在VCL体系中搭好了框架画自己,它会调用Paint;函数执行程序员的画图动作。
procedure Paint; virtual; // 虚函数,空函数。等待程序员填写画板的真正内容。框架已经由PaintWindow搭好了
property Canvas: TCanvas read FCanvas;
public
constructor Create(AOwner: TComponent); override; // 创建并设置内部画板
destructor Destroy; override; // 销毁内部画板和自己
end;