DelphiDelphi自定义控件开发(3)

2019-08-29 22:59

end;

procedure Register; implementation {$R *.res}

procedure LoadBitmapFromRes(ABitmapId: string; ABitmap: Graphics.TBitmap); begin

ABitmap.LoadFromResourceName(hInstance, ABitmapId);//从资源文件中读取位图 end;

constructor TLincoSwitch.Create(AOwner: TComponent); begin

inherited Create(AOwner);

FPicOn := Graphics.TBitmap.Create; FPicOff := Graphics.TBitmap.Create; LoadBitmapFromRes('SWITCHON', FPicOn); LoadBitmapFromRes('SWITCHOFF', FPicOff); Invalidate; end;

destructor TLincoSwitch.Destroy; begin

FPicOn.Free; FPicOff.Free; inherited; end;

procedure TLincoSwitch.Click; begin

IsOn := not IsOn;//改变按钮的状态 Invalidate; inherited; end;

procedure TLincoSwitch.Paint; begin

//画开关图案 if IsOn then

StretchBlt(Canvas.Handle, 0, 0, self.Width, self.Height, FPicOn.Canvas.Handle,

0, 0, FPicOn.Width, FPicOn.Height,SRCCOPY) else

StretchBlt(Canvas.Handle, 0, 0, self.Width, self.Height, FPicOff.Canvas.Handle,

0, 0, FPicOff.Width, FPicOff.Height,SRCCOPY); end;

procedure TLincoSwitch.FSetIsOn(AValue: Boolean); begin

FIson := AValue; Invalidate; end;

procedure Register; begin

RegisterComponents('Linco', [TLincoSwitch]); end; end.

3、代码分析

(1)、因为我们要在控件表面上将按钮的图案画出来,所以我们选择TcustomControl做为父类控件,因为它有个Canvas属性,我们可以利用Canvas在控件表面作图。不选用Tcontrol的原因是因为它有很多我们不需要的属性。

(2)、ABitmap.LoadFromResourceName(hInstance, ABitmapId);是从资源文件中读取Id为AbitmapId的位图,关于资源文件的使用请参考其他相关资料。注意代码中的“{$R *.res}”,它的作用是将资源文件编译到程序文件中,如果没有这个预编译条件,程序将会出现错误。

(3)、StretchBlt是将位图画到画板上,使用方法请参考MSDN。

(4)、我们为控件增加了IsOn属性。这个布尔属性用来表示开关的状态(开/关)。 从property IsOn: Boolean read FIsOn write FSetIsOn;我们可以看出这个属性是个可读可写的属性。当读这个属性时会将FisOn的值返回给调用者,而写属性时则会调用FsetIsOn方法,并将赋给属性的值做为参数传递给FsetIsOn。在FsetIsOn方法中,有如下实现代码: FIson := AValue; Invalidate;

首先将Fison设置为参数传递来的值,然后调用 Invalidate;要求重画控件,以告诉用户控件的状态已经改变,这一点是使用写字段无法做到的。 (5)

FPicOn: Graphics.TBitmap; FPicOff: Graphics.TBitmap;

是声明两个.Tbitmap类型变量以保存控件的开关两种状态的图案。 (6)

procedure Click;override; procedure Paint;override;

分别是覆盖父类中相应的调度方法。当控件被鼠标单击时,Click方法会被调用,我们将在Click中改变控件的开关状态;Paint方法则在用户调用 Invalidate方法或控件发生重画时调用,我们一般在这个方法绘制控件的图案。

(7)、TcustomControl中又很多事件处理句柄。比如OnClick、OnKeyDown等,但是它把他们声明成了Protected保护级别,所以我们在Object Inspector中看不到他们,如果我们要他们可以在Object Inspector中被用户编辑的话,只要在Published中重新声明他们即可,不用写他们的读写方法,只要使用:Property 属性名; 这样的方法就可以。比如这个例子中的:Property Onclick; 思考题:

1、 做一个有特效的按钮控件,当鼠标按下时按钮是一个红色边框的空心圆,当鼠标松开

时按钮是一个淡绿色边框的空心圆。

2、 对于父类控件中为protected的属性,如果想将它在子类控件中公布,应该怎么做?

请思考Delphi为什么要将一些属性设为protected级别?

Delphi控件开发浅入深出(四)

四、对特定字符串敏感的Edit控件

我们这个控件将演示控件的自定义事件的书写。这个控件有一个类型为string的SensitiveText属性,当用户在输入框中输入的文字为InvalidText时就会触发OnSensitiveText事件。按照惯例,我先把源码展示给大家:

unit TextSenseEdit;

interface uses

SysUtils, Classes, Controls, StdCtrls; type

TSensitiveTextEvent = procedure(AText: string) of object;//方法指针 TTextSenseEdit = class(TEdit) private

FSensitiveText: string;

FOnSensitiveText: TSensitiveTextEvent;

procedure SetSensitiveText(AValue: string); protected

procedure Change;override; public published

property SensitiveText: string read FSensitiveText write SetSensitiveText; property OnSensitiveText: TSensitiveTextEvent read FOnSensitiveText write FOnSensitiveText;

end;

procedure Register;

implementation

procedure Register;

begin

RegisterComponents('Linco', [TTextSenseEdit]); end;

procedure TTextSenseEdit.Change; begin

inherited;

if Text = SensitiveText then

if Assigned(OnSensitiveText) then OnSensitiveText(Text); end;

procedure TTextSenseEdit.SetSensitiveText(AValue: string); begin

FSensitiveText := AValue; end; end.

代码解释:

(1)、SensitiveText属性的添加方法大家已经熟悉了,这里不多解释。

(2)、正如大家猜测的,Change方法正是编辑框文字发生变化时的调度方法,它将引起OnChange事件。我们可以在这个方法中监控编辑框文字发生的变化,当文字等于SensitiveText就触发OnSensitiveText事件(具体的实现方法在后边解释)。

(3)、Delphi中的控件的事件机制是通过方法指针来实现的。声明方法指针的格式为: 方法指针名称 = procedure(参数列表) of object;

声明事件属性的方法与声明普通属性的方法相同。在我们这个例子中,我们首先声明一个FOnSensitiveText: TSensitiveTextEvent;私有变量,然后property OnSensitiveText: TSensitiveTextEvent read FOnSensitiveText write FOnSensitiveText; 声明事件属性。这样注册控件后,当用户把控件放到窗体中后,就会在Object Inspector中Evnets页中出现OnSensitiveText事件,我们就可以像使用其他事件一样使用这个事件了。

但是我们现在只是声明了一个事件属性,并没有书写任何代码来激发这个事件。我们应该在合适的时候激发此事件,显而易见我们应该在Change方法中激发此事件:

procedure TTextSenseEdit.Change; begin

inherited;

if Text = SensitiveText then

if Assigned(OnSensitiveText) then OnSensitiveText(Text); end;

当if Text = SensitiveText时就判断控件使用者是否为OnSetSensitiveText写代码了(准确的说是是否为OnSetSensitiveText事件句柄赋值了),如果写代码了则调用OnSetSensitiveText(Text);来激发OnSetSensitiveText事件,并把控件的Text传递给方法的Avalue参数。正如“方法指针”这个名字一样,被声明为方法指针类型的变量可以当作方法使用,用来激发事件。VCL已经为我们预定义了一些常用的事件句柄,我们直接拿来使用:TnotifyEvent,TmouseEvent,TmouseMoveEvent,TkeyPressEvent等,具体可以参考VCL源码。

思考题:

1、做一个支持累加运算的文本编辑框控件,用户可以在编辑框中输入正整数。当用户按回车时,如果编辑框中输入的不是正整数(为负数、小数或一般字符串)则触发控件的OnError事件;如果输入的是正整数,则开始计算从1到用户输入的那个正整数中所有整数的和(用1+2+3+??这种累加的办法实现,不要用(1+n)*n/2这种直接计算的方法),并且在计算工程中如果发现计算的中间结果位数是5,则触发OnTailFive事件。

Delphi控件开发浅入深出(五)

五、复合控件

复合控件是Delphi控件中非常重要的一种控件,复合控件就是将两个或两个以上的控件重新组合成一个新的控件。例如TspinEdit、TlabeledEdit、TDBNavigator等就是复合控件,TDBNavigator其实就是在一个Panel放上若干个Button而已。制作一个复合控件时,我们一般从TwinControl派生控件。

我们这次做的控件是拥有一个Edit编辑框和一个Button按钮的复合控件,在用户在编辑框中输入文字的过程中,Button将随时显示编辑框中文字的长度。我们把控件的源码先展示给大家。

unit EditButton; interface uses

SysUtils, Classes, Controls, StdCtrls, Messages; type

TEditButton = class(TWinControl) private

FEdit: TEdit; FButton: TButton; FText: string;

procedure FSetText(AValue: string);

procedure OnEditChange(Sender: TObject); protected

procedure WMSize(var Msg: TMessage);message WM_SIZE; public

constructor Create(AOwner: TComponent);override; destructor Destroy;override; published

property Text: string read FText write FSetText; end;

procedure Register; implementation

procedure Register; begin

RegisterComponents('Linco', [TEditButton]);


DelphiDelphi自定义控件开发(3).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:四川省情复习试题及答案

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: