DelphiDelphi自定义控件开发(6)

2019-08-29 22:59

begin

result := FDataLink.FieldName; end;

function TDBDateTimePicker.FGetDataSource: TDataSource; begin

result := FDataLink.DataSource; end;

function TDBDateTimePicker.FGetField: TField; begin

result := FDataLink.Field; end;

function TDBDateTimePicker.FGetReadOnly: Boolean; begin

result := FDataLink.ReadOnly; end;

procedure Register; begin

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

谈到开发数据敏感控件就不得不说数据连接(DataLink),数据连接有很多种,开发数据敏感控件最常用到的就是字段数据连接(TFieldDataLink)。数据连接是联系数据敏感控件和数据库的通道。在数据敏感控件中就是凭借着数据连接来处理数据的更新和显示的。从后边我们的描述中您将更加能体会到,正是数据连接把数据在数据库中的表示反映到用户界面中,也是数据连接把数据从用户界面更新到数据库中。数据连接就是一个“大媒人”(这其实是设计模式中Mediator中介者模式的典型应用)。

既然字段数据连接这么重要,我们就先来系统的介绍一下它吧!TfieldDataLink闪亮登场!!!

TfieldDataLink的属性:

(1)、property CanModify: Boolean;表示这个字段是不是只读的。

(2)、property Control: TComponent;指定这个字段数据连接被连接到哪个数据敏感控件。因为字段数据连接要把它的状态改变通知包含它的数据敏感控件。

(3)、property Editing: Boolean; 表示这个字段是不是可以被编辑。 (4)、property Field: TField;表示这个字段数据连接连接的字段。 (5)、property Active: Boolean;表示字段数据连接连接的数据集是否处于激活状态。 (6)、property FieldName: String;字段名。

(7)、property DataSource: TDataSource;表示它连接的数据源。 (8)、property DataSet: TDataSet;表示它负责维护的数据集。 方法:

(1)、function Edit: Boolean;尝试设置字段为编辑状态。如果设置成功则返回True,反之返回False;

事件:

(1)、property OnActiveChange: TNotifyEvent;当Active属性变化的时候发生此事件。

(2)、property OnDataChange: TNotifyEvent;当数据集发生变化的时候发生。 (3)、property OnEditingChange: TNotifyEvent;当数据源从编辑状态变为其他状态或从其他状态变为编辑状态的时候发生。

(4)、property OnUpdateData: TNotifyEvent;当向数据库提交对数据库的修改时发生此事件。

代码分析:

(1)、做为一个数据敏感控件,它首先要实现的功能就是允许用户将此控件连接到一个数据源(DataSource)。我们还要用户能选择这个控件绑定到哪个字段。

将控件连接到一个数据源,而数据源又是一个控件,所以这就是一个关联控件属性方法的应用。FsetDataSource中FDataLink.DataSource := AValue;这句代码是最重要的。就像我们前面讲到的数据连接就是一个在数据源和数据敏感控件之间的媒人,所以数据源(DataSource)要告诉媒人是它要被连接到数据敏感控件,而不是别人,告诉媒人的唯一方法就是设定媒人的DataSource为自己(即要绑定的数据源)。因为我们的显示日期的控件只能显示一个字段,还要告诉媒人自己的哪个字段要绑定到数据敏感控件,这个通过数据敏感控件的FieldName属性来进行。即:

procedure TDBDateTimePicker.FSetDataField(AValue: string); begin

FDataLink.FieldName := AValue; end;

(2)、我们还可以为控件增加一个Field属性,这样用户就可以通过

DBDateTimePicker.Field.AsString = ‘ok’;这样的方式对字段进行操作了。当然了,这最终还是通过数据连接的Field属性来进行的。

(3)、由于VCL内部通信机制的要求,数据敏感控件要响应CM_GETDATALINK事件。只要在事件相应函数里边把消息的Result域赋值为DataLink的地址就可以了。也就是:

procedure TDBDateTimePicker.CMGetDataLink(var Msg: TMessage); begin

Msg.Result := Integer(FDataLink); end;

(4)、就像DBEdit一样,在用户通过改变控件中的日期时,应该能将改动保存到数据库字段中。我们覆盖控件的调度方法Change(在显示的数据变化时被调用)以将变化保存到数据库中。

procedure TDBDateTimePicker.Change; begin

if (DataSource <> nil) and (DataField <> '') then begin

FDataLink.Edit;//设置数据连接为编辑状态,由这个媒人将数据库绑定的字//段设置为编辑状态

Field.Value := self.Text;//设定数据字段的值 end;

inherited Change; end;

(5)、回头再来看看构造函数吧!

FDataLink.OnDataChange := DataChange;

FDataLink.OnEditingChange := EditingChange; FDataLink.OnUpdateData := UpdateData; FDataLink.Control := self;

前三句是设定响应数据连接事件处理句柄,正是这三句把数据库中的数据与用户界面联系了起来。关于这三个事件处理句柄的实现请参加源代码,这里就不多说了。

思考题:

1、做一个显示是/否的数据敏感控件,当这个控件与一个布尔类型的字段连接的时候,如果字段的值是0则显示“否”,如果字段的值是1则显示“是”;同时可以接受用户的修改,当用户在控件上单击一次鼠标,布尔值就翻转一次。

Delphi控件开发浅入深出(结束语)

八讲的内容这么快就讲完了,通过这八讲相信大家对于Delphi控件开发有了大体的了解。但是仅仅了解还不够,要自己去发现:我做的程序中有没有可以提炼成控件的东西?一旦发现有可以提炼成控件的东西,就要尽力将它抽象化成控件。这样将能成倍甚至成十倍的提高系统的开发进度。

这篇文章其实是我去年写的,当时发在了我的个人网站上,但是由于空间到期了,我就一直没有理他。昨天注册了一个blog,所以想把这些东西再放出来,希望能给需要它的朋友带来一点帮助。

我在实际的开发系统中开发了很多实用的控件,但是由于blog空间的限制没有办法把他们上传上来,需要的可以给我留言或者给我发送email。

如何用Delphi编写自己的可视化控件

可视化控件(Visual Component)实际上就是一个类(class),要编写一个类,可以直接在*.pas文件中编写。但是要编写控件,则必须使用包(package)。从File菜单中选择New,新建一个Package,这就是存放和安装控件用的包。然后单击Package窗口中的Add按钮,添加一个元件(Unit)。

在弹出的对话框最上方选择New Component。因为一个控件的所有属性、方法、事件不可能都由自己编,所以就需要选择祖先类(或者叫做\父类\或\基类\),然后再在其上面添加自己的属性、方法、事件。在Ancestor type后的下拉框中选择所需的祖先类。由于编写可视化控件必须要画图,所以选择TGraphicControl作为祖先类。再在Class Name框中输入新控件(类)的名称,一般以\开头。Palette Page是用来选择新控件在Delphi的窗口中的控件页面名称,例如\,这个可以自己取。在Unit File Name中添好新控件文件的路径及文件名,单击OK按钮。新的控件便加入了。现在可以为该控件编写代码了。

下面以编写一个可以自定义图片的滚动条为例,说明编写可视化控件的方法。 按照上面的方法,选择TGraphicControl为祖先类,新控件的名称是TPigHorizontalScroller(小猪水平滚动条)。选择好文件路径和文件名后,单击OK按钮,开始编写代码。

每一个控件,都会被创建(Create)和删除(Destroy),所以必须首先编写这两个过程。对于控件中的每一个过程,都必须在前面先定义,然后再在后面编写。定义的过程或属性有三种:一、在private后定义的是属于控件内部使用的,使用该控件的人无法看到;二、在protected后定义的一般是看不到的,只在别人使用该控件作为祖先类编写其它控件时才可见;三、在public后定义的只允许别人在程序中调用;四、在published后定义的可以在属性窗口(Object Inspector)中看到。由于创建和删除过程除了在编程过程中建立控件时自动执行外,还可能在程序运行过程中动态创建控件时被调用,所以把它定义在public后⑴。(该序号表示次步骤在所附源程序中的代码的位置,下同)现在也许还不知到应该在这两个过程中编写什么,如何去编。我们在下面将会讲到。

我们首先为这个控件添加一些属性。我们定义一个Max属性用于设置或读取滚动条的最大值。因为在程序中一般不直接使用属性,所以要定义一个变量,和该属性对应起来,一边修改或读取其值。因为它只在控件内部使用,所以我们把它定义在private后⑵。(一般与属性相关联的变量都以\开头,例如FMax)定义好变量后,再定义属性。这个属性需要再Object Inspector窗口中可见,所以把它定义再published后⑶。定义的语法是:

property <属性名>:<类型> read <读取该属性时对应的变量> write <写入该属性时对应的变量或过程>

其它的变量和属性也类似的定义(例如Min最小值、Value当前值等)。下面我们定义几个属性和变量,用于设置滚动条的图片(因为图片变量比较特殊,所以单独讲一下)。我们把LeftButtonUpPicture(向左按钮图片)、LeftButtonDownPicture(向左按钮按下图片)

等定义为TBitmap类型(一定要定义相对应的变量)。

大家一定注意到了,在所附的源程序中,定义这几个属性时,read后所指定的读取属性时对应的变量是F…,而write后指定的写入该属性时对应的不是一个变量,而是一个Set…之类的东西,这是一个自定义的过程。作为该功能的过程的定义为:

procedure <过程名>(Value: <被设置的属性的值的类型>)

因为执行写入该类属性的时候需要做其它的事情,所以不能光用一个变量来处理,应该用一个过程来处理。这中过程一般定义在protected后。在该类过程中,使用一个在⑷处这样一个语句来给TBitmap类型的变量来赋值,这是由于该类型的变量不能直接赋值而采用的。

定义完这些TBitmap类型的变量的属性后,上面讲的create过程和destroy过程中就需要编写代码了。因为TBitmap也是一个类,所以在create过程中必须创建⑸,在destroy过程中必须释放掉(free)⑹。这里⑺所指的inherited语句是用于指明该过程是从祖先类类中继承来的。(这个一定不能掉)。

因为我们编写的是可视化控件,所以必须在控件上画图。我们这个控件的祖先类TGraphicControl中封装有一个Canvas(画布)对象,我们可以直接使用它来画图。如果你对画布的使用还不太熟悉,最好去找一本书来看一看。

下面要做的工作就是画图了。如何在控件上画图呢?祖先类TGraphicControl中有一个Paint事件,当控件需要重画时便会自动触发。我们现在要做的就是要为这个事件编写一段程序。首先在protected后定义一个Canvas对象。由于它是祖先类中已有的,所以不需要加任何说明⑻。我们将使用这个对象来画图。接着,就要定义一个Paint过程,编写绘制控件的代码。先在public后定义Paint过程。由于它是由祖先类触发的,而不是由用户调用的,所以后面必须加上override,否则,该控件将会由于Paint过程永远不会被调用而不成为可视化控件⑼。下面我们就来编写Paint过程的代码⑽。

该文章所附的源程序的Paint过程中的T_Height等变量是用来保存滚动条中按钮、滑块等的大小的,这部分程序和普通的Application中的程序差别不大,大部分都是对画布进行操作,相信大家一看就明白。值得注意的是下面对FAutoSize变量的判断⑾,FAutoSize是和该控件的属性AutoSize相关联的布尔型变量,是用来设置这个控件的大小是否随图片的大小而变化的。注意,在控件的代码中,一般都不直接调用属性,而是使用与其相对应的的变量。

程序编到这里,就算是终于给自己的新控件做了一个外型了,不过它还不能滚动。现在我们来编写鼠标事件,让我们能够操纵它。鼠标事件的过程的定义和Paint过程很相似,只是后面要加上参数说明⑿,鼠标事件分为MouseDown、MouseMove和MouseUp三个,在定义后面都要加上override。接下来在后面编写它的代码。注意:这里的鼠标事件是Mouse…,而不是通常的OnMouse…。可是在⒀处的定义是干什么用的呢?这里的事件定义,都是给用户使用的,也就是说,当使用该控件时,会在Object Inspector中的Event页面中显示出来。

这些鼠标事件的代码也非常简单,判断鼠标的坐标,在画布上画出相应的图片等,并同时触发相应的事件。值得注意的是,在调用自定义事件时,都要先用⒁处的这样一个语句来判断用户是否已经为该事件编写代码。这一点非常重要,否则会调用出错。

大家注意到了,刚才所调用的事件都是自定义的,定义的方法也很简单,和定义属性差不多,只是类型时TNotifyEvent罢了。

TNotifyEvent是默认事件,其定义为:

TNotifyEvent = procedure(Sender: TObject)

如果你要定义另外形式的事件,就必须这样:先在type后编写

<事件类型名称> = procedure(<参?gt;:<类型>)

例如:

TCustomEvent = procedure(a: Integer; b:String);

然后在public后定义:

<事件名称>:<事件类型名称>

例如:

AnEvent: TCustomEvent;

看完这些,这整个程序你应该理解了吧。如果编译或运行出错,注意检查以下几点:

1、create和destroy过程中是否有inherited语句; 2、TBitmap类型的变量create和free了没有;

3、过程前有没有控件名,例如:TPigHorizontalScroller.MoseMove

判断鼠标是否进入或离开控件的方法:

定义如下的过程:

procedure MouseEnter(var Msg: TMessage); message CM_MOUSEENTER; procedure MouseLeave(var Msg: TMessage); message CM_MOUSELEAVE;

再在下面编写代码就行了。这个方法用于编写三态按钮很有用。


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

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

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

马上注册会员

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