Delphi控件开发基础篇
Delphi中控件(Component)是依托于 VCL(Visual Component Library)框架而出的。其根类是TComponent。
大凡控件都是从如下几个类继承得来。 TGraphicControl
在实际的界面开发工作中,有许多简单的控件,其本身仅仅是简单的显示一些提示信息,不会完成什么复杂的工作,譬如 TLabel,TPaintBox等控件;而对于win32开发来说,窗口句柄是有限且宝贵的资源,其创建,使用及销毁 成本太高。所以需要一种无句柄的操作模式,且可以自绘的能力, TGraphicControl完全满足这一点。
TGraphicControl的自绘能力由FCanvas负责。并且由WMPaint消息函数调用。各位读者可能会有疑问,TGraphicControl并非Windows窗口类,它怎么能处理消息呢,关于这一点,就不得不提VCL的变态之处,从TComponent 中提供了一套控件自身的消息传递机制—Perform。它扮演者类似于Windows的消息分发函数 DispatchMessage的角色。 最后的绘制工作,落到Paint函数头上,这是个虚拟函数(也算是抽象函数,此处使用了 Spacehold 占位符技术),所以 WMPaint和Paint提供了绘制框架, 此类控件的具体绘制工作,是由后代的Paint函数负责。下面查看一下 TPaintBox的代码,验证一下我们的猜测。
TGraphicControl = class(TControl)
private
FCanvas: TCanvas;
procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
protected
procedure Paint; virtual;
property Canvas: TCanvas read FCanvas;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
end;
constructor TGraphicControl.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FCanvas := TControlCanvas.Create;
TControlCanvas(FCanvas).Control := Self;
end;
destructor TGraphicControl.Destroy;
begin
if CaptureControl = Self then SetCaptureControl(nil);
FCanvas.Free;
inherited Destroy;
end;
procedure TGraphicControl.WMPaint(var Message: TWMPaint);
begin
if Message.DC <> 0 then
begin
Canvas.Lock;
try
Canvas.Handle := Message.DC;
try
Paint;
finally
Canvas.Handle := 0;
end;
finally
Canvas.Unlock;
end;
end;
end;
procedure TGraphicControl.Paint;
begin
end;
通过代码可以看出,TPaintBox控件很简单,仅仅提供了Paint函数,以及由它调用供使用者自定义绘制的OnPaint函数。提供了外部绘制接口。
这类组件不能成为其他控件的父类。
这类控件的绘制依赖父类画布能力。受父类影响很重。
TPaintBox = class(TGraphicControl)
private
FOnPaint: TNotifyEvent;
protected
procedure Paint; override;
public
constructor Create(AOwner: TComponent); override;
property Canvas;
published
property Align;
... {把父类的属性 发布出去}
property OnPaint: TNotifyEvent read FOnPaint write FOnPaint;
end;
constructor TPaintBox.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
ControlStyle := ControlStyle + [csReplicatable];
Width := 105;
Height := 105;
end;
procedure TPaintBox.Paint;
begin
Canvas.Font := Font;
Canvas.Brush.Color := Color;
if csDesigning in ComponentState then
with Canvas do
begin
Pen.Style := psDash;
Brush.Style := bsClear;
Rectangle(0, 0, Width, Height);
end;
if Assigned(FOnPaint) then FOnPaint(Self);
end;
TWinControl
VCL中所有封装Windows控件的组件 都是从这个类中继承而来,并最终的绘制都有Windows来完成,这些组件只是提供一个封装转化接口,以适应Delphi使用形式,扩充了使用外延。所以它不带有Canvas属性和 Paint方法。比如 TButton,TEdit等控件都是如此。且这些组件的代码位于 StdCtrls单元。
TCustomControl
那么如果我既想要Windows帮我绘制,还得自绘一些东西,算是定制化的window控件,该怎么办呢,那叫让它从TCustomControl继承吧。它既能让Windows帮你完成基本绘制,也可以自己在此基础上个性化绘制。比如 TPanel组件就是从此继承得来。并且界面刷新及时。
其代码和TGraphicControl,及其类似。只不过他还提供PaintWindow函数。以及知名csCustomPaint属性。
TCustomControl = class(TWinControl)
private
FCanvas: TCanvas;
procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
protected
procedure Paint; virtual;
procedure PaintWindow(DC: HDC); override;
property Canvas: TCanvas read FCanvas;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
end;
{ TCustomControl }
constructor TCustomControl.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FCanvas := TControlCanvas.Create;
TControlCanvas(FCanvas).Control := Self;
end;
destructor TCustomControl.Destroy;
begin
FCanvas.Free;
inherited Destroy;
end;
procedure TCustomControl.WMPaint(var Message: TWMPaint);
begin
Include(FControlState, csCustomPaint);
inherited;
Exclude(FControlState, csCustomPaint);
end;
procedure TCustomControl.PaintWindow(DC: HDC);
begin
FCanvas.Lock;
try
FCanvas.Handle := DC;
try
TControlCanvas(FCanvas).UpdateTextFlags;
Paint;
finally
FCanvas.Handle := 0;
end;
finally
FCanvas.Unlock;
end;
end;
procedure TCustomControl.Paint;
begin
end;
TComponent
前面讲了那么多,但是都是可视化组件,但是还有一类组件,视为非可视化组件,他们不涉及界面交互方面的事,典型的有TTimer等。所以他们从TComponent 继承 即可。
TTimer = class(TComponent)
private
FInterval: Cardinal;
FWindowHandle: HWND;
FOnTimer: TNotifyEvent;
FEnabled: Boolean;
procedure UpdateTimer;
procedure SetEnabled(Value: Boolean);
procedure SetInterval(Value: Cardinal);
procedure SetOnTimer(Value: TNotifyEvent);
procedure WndProc(var Msg: TMessage);
protected
procedure Timer; dynamic;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property Enabled: Boolean read FEnabled write SetEnabled default True;
property Interval: Cardinal read FInterval write SetInterval default 1000;
property OnTimer: TNotifyEvent read FOnTimer write SetOnTimer;
end;
|
请发表评论