DELPHI构件制作方法
发信人: pitts (痛并快乐着), 信区: Delphi
标 题: DELPHI构件制作方法
发信站: BBS 水木清华站 (Tue Oct 13 10:19:36 1998)
Delphi作为RAD工具,以其快速编译和友好的可视化界面受
到广泛欢迎。Delphi提供了很多现成构件,而且随着版本更新不
断增加新构件。另外还可以买到第三方开发的特色构件,或从因特
网下载免费构件。这些构件足以支持一般应用系统开发。但应用开
发人员仍有必要自己制作构件。
采用构件形式可以把对象严密封装,并加上一层直观外壳,有
利于软件调试和代码重用。开发群体以构件为功能单位分工协作,
比较容易实现工程化管理,从软件规划设计到测试修改都可以减少
意外差错,大大提高工作效率。成熟的构件还可以作为商品软件出
售,带来附加效益,且有利于软件开发的社会化分工协作。Delphi
的构件使用和构件制作采用同样的工作环境和相似的编程方法,只
要弄清基本原理,制作构件无需学习多少新东西。
基本概念
制作构件的基本过程可以概括为:
1.编写构件单元(unit)。其中包含构件声明和构件实现代码。
2.按照与普通Delphi单元同样的方法编译和调试构件单元。
3.创建构件注册单元。其中用uses语句连接构件单元,并用
Register过程完成构件的注册。
4.编写构件联机帮助信息,并编译成标准Windows帮助文件。
全部工作完成后,生成构件单元二进制文件(.DCU)、构件注
册源文件(.PAS)和帮助信息文件(.HLP)及附加的关键词文件
(.KWF)。用户拿到这些文件后,就可以安装使用了。在Delphi
环境下调用菜单命令,启动安装过程(安装过程中需指定注册文件
名),可以把构件注册到Delphi的VCL库中,并在构件工具条上生
成一个新按钮。借助HelpInst安装工具可以把关键词文件并入
Dephi帮助索引系统,用F1键实现联机帮助。
这样制作出的.DCU文件与一般Delphi单元没有根本区别,
即使不安装到VCL库中也可以由其他单元直接调用。最大的区别在
于:构件单元中某些属性和事件声明为published,从而在程序设
计期对用户是可见的,用户可以通过对象编辑窗口
(ObjectInspector)访问这些属性和事件。这是可视化程序设计
的关键所在。
对象的继承与修改
制作构件第一件事就是选择适当的Delphi对象类型作为父对
象,以派生新的对象。子对象可以继承父对象的全部非private部
件,但不能摆脱不需要的部件。因此,所选父对象应尽可能多地包
含子对象所需的属性、事件和方法,但不应包含子对象不需要的东
西。
TComponent是所有Delphi构件的基点,但若直接从TComponent
派生新构件,很多东西就需要自己从头做起。一般只有非可视构件
才直接从TComponent派生。Delphi提供了若干专门用于制作控件
(可视构件)的对象类型,都是从TControl和TWinControl派生
而来。其派生关系如下:
TControl---TGraphicControl---TCustomLabel
TWinControl--TCustomControl---TCustomGrid
---TButtonControl--TCustomGroupBox
---TScrollingWinControl--TCustomPanel
---TCustomComboBox
---TCustomEdit
---TCustomListBox
TControl的子类型用于非窗口式控件,TWinControl的子类型
则用于窗口式控件。除非特殊需要,一般不直接从TControl和
TWinControl派生新控件,而是从其子类型派生。这样可以充分利
用原有的属性、事件和方法,减少很多工作量。
在这些构件类型中,非通用的属性、事件和方法都声明为
protected。这样可以禁止构件用户访问,又能被子类型继承和修
改。在新构件中,可以简单地把继承来的属性和事件重新声明为
published,使构件用户能在设计期通过对象编辑窗口访问,也可
以进而修改属性的默认值和读写方式,或是重载(override)事件
处理子过程和其他构件方法,以修改其中的程序代码。重声明可以
放宽访问权限,但不能 相反,例如,不可能把published属性
重声明为private或protected。
为了增加新功能,常常需要定义全新的属性、事件和方法。定
义时,一般总是把对用户开放的属性和事件声明为published,把
方法声明为public或protected。
构件属性
在构件中,属性和方法往往可以相互替代。对构件用户来说,
属性比方法更直观简便。因此,只要可能,应尽量以属性取代方法。
属性类型包括简单类型(numeric,character,string)、枚
举类型、集合类型、对象类型(例如font)和数组类型(例如TStrings
类型中的Strings)。其定义方法如下:
type
private
FLayers:Integer;{内部存储用的变量}
functionGetLayers:Integer;{用来读属性值的方法}
procedureSetLayers(ALayers:Integer);{用来写属性值的
方法}
published
propertyLayers:
IntegerreadGetLayerswriteSetLayersdefault1;
end;
每个属性都需要相应的private变量用于内部存储。按照约
定,变量名以F打头,后跟属性名(此处为Layers),读写方法名
称分别为Get加属性名和Set加属性名。写方法总是带一个与属性
类型相同的参数,用以传送属性值。此参数可以传值,也可以传递
变量。如果不定义写方法(省略write部分),此属性便成为只读
属性。读写方法应该在private部分声明,以使其对构件用户
和构件的派生对象保持隐蔽。
读写方法除了取值和赋值之外,还可以附加其他操作代码,使
属性读写产生附加效应。这正是属性可以取代方法的原因。如果不
需要附加效应,可以不定义读写方法,采用直接访问格式来声明属
性:
propertyLayers:
IntegerreadFLayerswriteFLayersdefault1;
default命令符用来指定属性的默认值,同时需要在构件的构
造函数中为属性设置初值。default命令的作用是在窗体文件存盘
时提供参照:若属性当前值与default命令指定的值不同,则把当
前值保存在文件中,否则便无需保存。如果省略default命令,属
性当前值总是保存在窗体文件中。
事件与事件处理过程
创建构件时,事件也被当做属性来处理,区别仅在于事件必须
定义为过程类型,使其成为一个隐蔽指针,指向某个潜在的过程。
当构件用户为事件指定处理子程序后,事件便成为指向该子程序的
指针。事件的定义方式如下:
type
private
FOnClick:TNotifyEvent;{声明事件变量以保存过程指针}
published
propertyOnClick:
TNotifyEventreadFOnClickwriteFOnClick;
end;
此例正是Delphi标准控件中Click事件的定义方式。可以看
出,除了OnClick被定义为过程类型外,其定义格式与一般属性的
直接访问格式几乎完全相同。Delphi预定义了所有标准事件的过
程类型及标准事件所引发的虚方法。其中,Click事件将引发如下
虚方法:
procedureTControl.Click;
begin
ifAssigned(OnClick)thenOnClick(Self);
{以下是默认处理部分}
end;
其中,Assigned函数检验OnClick是否已分配了事件处理过
程。如果返回值为True,则调用用户指定的事件处理过程。通过
重载此虚方法,可以修改Click事件的处理方式。在重载的方法中,
一般应先调用用户处理程序,然后再安排后续处理。在本例中,首
行代码应当是inheritedClick。
需要注意的是,构件用户不一定会给事件指定处理程序,因此
事件不能定义为函数类型,否则可能会指向返回值类型不定的空函
数。如果需要事件处理过程返回某个值,可以借助var参数。调用
用户程序之前应确保此参数包含有效返回值,以免用户未指定事件
处理过程时出错。
如果Delphi标准事件不能满足需要,也可以自己定义事件。
其核心思想是选择适当的Windows消息来引发构件中的事件过程。
篇幅所限,不拟详述,请读者参阅有关资料。
方法处理要点
方法处理在创建构件时和使用构件时没有多大区别,但有些问
题仍需要注意。
首先要注意的是,构件通常是在事件处理过程中调用,而构件
作者又无法预测用户将在什么环境下如何调用构件。因此,构件中
的方法应尽量避免占用系统资源,避免使Windows停止对用户操作
的反应。
创建构件时应随时意识到,此构件不仅可以直接调用,而且可
用来创建别的构件。即使是对用户隐蔽的方法也应具有完整的功能
和清晰的接口。除了属性读写方法之外,内部方法一般应声明为
protected虚方法,以便被派生对象继承和重载。属性读写方法则
应采用private声明严密保护。派生对象如果需要读写父对象的属
性值,应该访问属性本身,没有必要直接访问其读写方法。
构件测试
制作构件的核心工作是编写构件单元,包括根据构件功能要求
设定对用户开放的属性、事件和方法,设定用以实现这些部件的变
量、过程和函数等等。除了属性和事件有 特殊格式之外,构件
单元的设计方式与一般Delphi单元没有什么不同,只是单元中不
能包含窗体。
在编写构件单元的过程中,可以借助一个测试窗体直接对其测
试。以可视化方法在窗体上安排构件,本质上不过是自动生成调用
构件的代码。即使构件未并入VCL库,无法使用可视化操作,也可
以手工编写这些调用代码。这样测试,可以免去反复修改而导致的
反复安装。
测试时,需先建立一个窗体单元,然后进行以下操作:
1.把被测构件单元名称加入窗体单元的uses语句中,并在
public部分声明被测构件的对象实例。
2.在窗体单元的FormCreate子程序中调用被测构件的Create
方法,以构造构件实例,其Owner参数设置为Self,即窗体本身。
然后给Parent属性赋值,并适当设置其他属性值。Parent是容纳
构件的父对象,如果是窗体本身,应设置为Self。
3.运行包含测试窗体的工程,找出构件程序中的错误。
注册构件
注册构件用的程序代码可以放在构件单元中,但在Delphi下
注册构件时要求提供包含注册代码的源程序文件(.PAS文件),
因此,比较好的方式是把构件核心代码编译成.DCU文件或.DLL
动态链接库,在注册源文件中只放注册代码和外围程序。下面是注
册代码实例:
type
TMyPanelΚclass(TCustomPanel)
TMyLabelΚclass(TCustomLabel)
procedureRegister;
implementation
procedureRegister;
begin
RegisterComponents(′Samples′,[TMyPanel,TMyLabel]);
end;
注册过程名必须是Register。过程体中调用Register
Compnents,其中的两个参数分别指定Delphi构件工具条页名和要
注册的构件类型。如果指定页不存在,Delphi将创建一个新页。
Delphi环境提供了一个构件生成器(componentexpert),
可用来自动生成注册单元。
构件工具条上每个构件需要一个24×24点阵bitmap图标。图
标可以借助Delphi的ImageEditor编辑生成,以.DCR资源文件
的形式提供给构件用户,文件与注册单元文件相同。如果不提供此
文件,Delphi将采用默认图标。
提供联机帮助
一个成熟的构件,无论是用于开发群体还是用做商品软件,都
要有联机帮助信息才能正常使用。Delphi的帮助信息与Windows
一般帮助信息结构基本上相同,其编写方法可参见有关资料。但
Delphi包含一个特殊的帮助搜索引擎,能跨越多个帮助文件搜索
关键词。因此,在构件帮助文件中不仅要有普通K型关键词脚注,
还要包含Delphi所用的B型关键词脚注。脚注内容有如下约定:
在Delphi的对象编辑窗口和代码编辑窗口中,用F1键可以引
发帮助搜索引擎,通过B型关键词调出有关帮助主题。为了实现这
种帮助机制,需借助KeywordGenerate程序来生成关键词文件
(.KWF),与帮助信息文件(.HLP)一起交给构件用户。用户借
助HelpInst程序把关键词文件内容并入Delphi主帮助索引文件
(.HDX)中。
构件联机帮助信息应当与Delphi标准构件帮助信息格式相
同。编写帮助文件时最好遵循如下约定:
1.每个构件有一个单独的帮助主题(Topic),内容包含构件
简介及用户可见的属性、事件和方法列表。
2.新增的及修改较大的属性、事件和方法均应有单独的帮助
主题,其中应包含所属构件、用途、声明格式等内容。
3.每个帮助主题都应包含K型脚注,以便用F1键引发。