第 11章 组件开发技术本章要点:
组件的概念
开发组件的一般步骤
Delphi中的相关类
创建组件单元的方法
为组件添加属性,事件和方法
组件的调试与安装
11.1 循序渐进学理论
11.1.1 组件与组件技术概述
1.组件概念组件是模块化程序设计方法发展到一定阶段的产物,在软件工程的角度来考虑,开发者总是希望把一个庞大的应用程序划分成多个模块。其中,每个模块都保持一定的功能独立性,在协同工计良好的应用系统往往被切分成一些组件,这些组件可以单独开发、
单独编译,甚至单独调试和测试。当所有的组件开发完成后,把他们组合在一起就得到了完整的应用系统。
当系统的外作时,通过相互之间的接口来完成实际的任务。我们把每一个这样的模块称之为组件 。
2.从一个实际的组件看组件的组成
( 1)组件的声明组件的声明其实就是类的声明。代码的一开始用
Class声明了一个名为 TButton的类,该类的基类是
TButtonControl。类的成分有四种,分别是 Private、
Protected,Public和 published。
( 2)方法在组件中用 Procedure或 Function定义的过程或函数均是方法,方法可以被外界调用。
( 3)属性在组件的定义中需要特别注意的是 property关键字,
该关键字用于组件属性的声明,声明属性时可用 read
关键字标识了属性的读取方法,用 write关键字标识属性的赋值方法。如代码中的语句:
property Default:Boolean read FDefault write SetDefault
default False;
( 4)事件事件是一类特殊的属性,实际上它是一个函数或过程的指针,也可以是系统指供的特定的名称。如代码中的语句:
property OnMouseDown;
property OnMouseMove;
3.开发组件的一般步骤创建一个组件,大致可以分为以下 6个步骤 。
( 1) 确定一个基类 。
( 2) 创建一个组件单元 。
( 3) 在新组件中添加属性,方法和事件 。
( 4) 测试该组件 。
( 5) 在 Delphi中注册该组件 。
( 6)为该组件建立帮助文件。
11.1.2 确定组件基类
1,Delphi组件结构
2.几种常用的基类
( 1) TWinControl类
TWinControl对象的特征,
① 有窗口句柄
②能够接受输入焦点
③能够作为其他组件的父组件
( 2) TGraphicControl类
TGraphicControl是图形组件类,图形组件也属于可视组件,但它与 TWinControl有很大不同,它没有句柄,不能获得焦点,也不能作为其他组件的父组件。
这类组件的缺点是难以和用户交互,其优点是节省系统资源,而且有较快的图形绘制速度。
( 3) TCustomControl类常用的可视组件一般都从以 TCustom开头的类派生,
实际上在 TCustom类中已经实现了组件的属性、方法和事件,只不过它们的成员都是 Protected,即对于外部是不可见的,无法被使用,而在它的派生类里才将这些属性和方法公开。
下面我们通过开发一个实际的剪切板文字查看组件来说明组件的开发过程。剪切板查看组件具有以下功能:
( 1) 该组件的基类是 TPanel组件,能够通过属性设置它的标题和是否可见,组件名为,ClipBoardViewer”。
( 2)当剪切板中存放的是文本信息时,且当文本发生变化时,将发生一个名为 ClipBoardChangeText的事件,该事件有一个参数 Text用来传递剪切板上的数据。
11.1.3 创建组件单元用户可以自己编写一个实现组件类功能的组件单元,但这比较麻烦。用户也可以通过菜单来创建新组件单元,创建的步骤如下:
( 1)执行 【 Component】 → 【 New Component】 菜单命令。将会出现 【 新建组件 】 对话框。
( 2)指定组件的基类。指定方法是在 【 Ancestor type】
后面的列表框中选择相应的基类名,本题选择
TCustomPanel。
( 3)设定组件名。在 【 Class Name】 后面的文本框中输入类名,本题输入的类名为,TClipBoardViewer”。
( 4)设定组件出现在哪一个组件页中。在
【 Palette Page】 后面的列表框中可以选择一个组件页,
本题选择 【 Samples】 组件页,该组件注册过后将会出现 【 Samples】 组件页中。
( 5)指定组件单元的保存位置和名称。在 【 Unit
file name,】 后的文本框中输入组件单元存放的路径和单元文件名,单元文件名和类名相同(不包含开头的字母 T)。
( 6)自动创建组件单元。设置完成后如图 11-3所示,此时按 【 OK】 按钮系统将自动创建组件单元。
11.1.4 创建包工程包工程是组件的容器,组件一般由包工程来安装和发布。包工程的主要用途就是封装 Delphi的组件,
组件包工程的扩展名为,dpk,Delphi自带的组件都打包在 Delphi的 Lib目录的 Delusr.dpk文件中。
下面创建一个包工程用来容纳并测试创建的
TClipBoardViewer组件,打包的方法如下:
( 1)执行 【 File】 → 【 New】 → 【 Other】 命令,
在出现 【 New Items】 对话框中选取 【 Package】 图标,
然后按 【 OK】 按钮,此时将会出现包工程管理器窗口。
( 2)单击 【 Add】 按钮,将会出现 【 Add】 对话框,在该对话框的 【 Unit file name】 后面的文本框中输入组件单元的文件名或通过单击其后的 【 Browse… 】
按钮来选择一个组件单元文件名。输入或选择
,E:\ClipBoardViewer.pas”。
( 3) 保存包工程,工程名文件为,Package1.dpk”。
( 4)单击 【 Compile】 按钮对组件单元进行编译,
若无错误则编译并注册组件。也可以直接按 【 Install】
按钮来注册组件。
11.1.5 在组件中添加属性
1.属性的类型属性是用户用来访问组件内部存储域的接口。通过属性,组件使用者能够修改或读取存储域的值。
组件的属性一定具有某种类型,Object Pascal语言中的数据类型规则同样适用于属性,属性的类型决定了它的值在对象观察器中如何设置。属性的类型如表 11-1所示。
属性类 型类型说明简单 包括整型,浮点型,实型,字符型和字符串型等基本类型,在对象观察器中可以直接输入属性的值 。
枚举 枚举类型 ( 包括 Boolean) 的属性在源代码中定义它的值 。 在对象观察器中,用户可以通过双击属性值栏来查看所有可能的值并进行设置,也可以从其下拉列表中浏览全部可能的值并设置 。
集合 用户可以展开集合类型的属性,并把每一个集合元素看成一个 Boolean型:值为 True时,表示集合包含这个元素,值为
False时,表示集合不包含该元素 。
对象 对象属性必须由 TPersistent类派生 。 编辑对象类型的属性常常需要有它们自己的属性编辑器 。 然而,如果对象本身的属性也是公开的,则在对象观察器中允许用户展开这个对象类型的属性并分别编辑它们 。
数组 数组属性必须有它们自己的属性编辑器,在对象观察器中无法编辑这种类型的属性,数组类型的属性是在类的 Public部分声明的 。
表 11-1 属性类型及其说明
2.简单属性的声明下面我们为该组件创建三个属性 BorderWidth、
Caption和 Visible,其中 BorderWidth的类型为整型,
其它两个属性是系统属性,用来设置标题和可见性。
代码编写好后,在包工程中编译该组件,然后新建一个工程,在窗体上添加一个 TClipBoardViewer组件,选中该组件,对象观察器窗口如图 11-8所示。
注意:对于用户定义的属性来说,一般要在类的
Private部分定义一个存储该属性值的变量,变量名一般以 F开头,如本题的,FBorderWidth”。
图 11-8 填加若干个属性后的对象及对象观察器
3.枚举型和集合型属性的声明枚举型属性的设置 集合型属性的设置
4.数组属性的声明可以为组件添加数组属性,数组属性的实现与简单类型属性的实现方法有一些不同,给属性设置值其实是设置数组元素的值,读取属性的值其实是读取数组元素的值,为标识读写的是数组属性的哪一个元素,
读写方法中应增加一个表示数组元素下标的参数。
下面使用该组件给数组属性的每一个元素赋一个随机的两位数,然后求数组属性各元素值的平均值。
可按照以下步骤来实现:
( 1) 重新在包工程中编译组件单元;
( 2) 新建一个工程,在窗体 Form1上添加该组件,然后再添加一个各为 Button1的按钮组件 。 设置 Button1的标题为,求平均,。
( 3) 再在窗体上添加一个名为 Label1的标签组件,用来显示求得的平均值 。
( 4)编写按钮组件的 OnClick事件代码 。
( 5)运行程序,单击 Button1按钮,程序的执行结果如图 11-11所示。
图 11-11 数组属性演示程序执行结果
5.对象属性的声明组件的属性还可以是对象,对象的使用比较复杂,在使用之前要创建对象,在使用过后要释放对象,这都要在组件中自动实现 。
一般是在类的构造器中创建对象,在析构器中释放对象 。
11.1.6 在组件中添加事件
1.事件的来源事件是一种特殊的属性,当某个动作发生时,就会执行预先指定的代码。事件可能是由用户交互操作、
操作系统、程序代码等产生。事件的机制就是事件与相应的代码相联系,当事件发生时,就会调用相应的代码。事件与代码的链接称为事件属性,以方法指针的形式提供。而这样的代码就是处理事件的方法,称之为事件处理过程。
2.确定事件类型事件类型 说明
TNotifyEvent 通知事件类型,是大多数事件的类型,只有一个
Sender参数
TMouseEvent 鼠标事件类型,会传递鼠标位置,按键等信息
TKeyEvent 键盘事件类型,传入按下键的代码
TCloseQueryEve
nt
关闭事件类型,允许给 CanClose参数赋值以控制窗体是否关闭
ThelpEvent 帮助事件类型
TdragDropEvent 拖动事件类型,会给出拖动源和拖动目标等信息
TcanResizeEvent 组件大小变化事件,允许给 Resize参数赋值控制是否改变组件大小
3.加入事件加 入 事 件 的 方 法与 属 性 的声 明 基 本 一致,例 如给 要 加 入
TClipBoardViewer组件添加 TClipBoardTextChangeEvent的代码如下:
TClipBoardTextChangeEvent=Procedure(Sender:Tobject;Text:String) of
Object;
TClipBoardViewer = class(TCustomPanel)
private
FOnClipBoardText:TClipBoardTextChangeEvent;
//……
published
property OnClipBoardText:TClipBoardTextChangeEvent read
FonClipBoardText
Write FonClipBoardText;
end;
4.触发事件在组件中使用标准事件时,不需要考虑触发事件,
由系统自动触发。对某些事件,触发条件是必须的。
例如,一个 MouseDown事件是在用户按下鼠标的左键时发生,Windows给应用程序发送
WM_LBUTTONDOWN消息。接到消息后,一个组件调用它的 MouseDown方法,再调用用户的
OnMouseDown事件处理过程代码。但是有些事件却不是那么容易描述清楚的。例如,滚动条有一个
OnChange事件,可被各种情况触发,包括按键、鼠标点击等。当定义事件时,开发者必须保证定义的事件能被正确地调用。
11.1.7 调试组件下面编写一个项目来测试编写的 TClipBoardViewer组件 。
新建一个项目,在该项目中添加一个 Memo组件和一个 TClipBoardViewer组件,程序的设计界面如图 11-12
所示 。 然 后 编 写 TClipBoardViewer 组件的
ClipBoardText事件代码,如下:
procedure
TForm1.ClipBoardViewer1ClipBoardText(Sender:
TObject;
Text,String);
begin
Memo1.Text,=Text;
end;
程序执行时,任意选中一些文本,然后按 Ctrl+C键,程序的运行界面如图 11-13所示。
图 11-12 程序设计界面 图 11-13 程序运行界面
11.1.8 制作组件图标和发布组件
1.制作组件图标组件创建好后,应为组件提供图标。可以通过
Delphi工具 Image Editor为组件创建图标,创建的图标是一个 24× 24的资源文件,其后缀名为 RES,应改为
DCR,并且组件图标的颜色也最好不要超过 16色。
创建了一个位图后,必须给这个位图命名。位图的名称要跟组件的类名相同,而且要大写。位图文件必须与组件的单元文件位于同一个目录下,编译这个单元时,位图资源会被自动加到组件库中。
例如为 TClipBoardViewer组件创建的 24× 24的位图的名称应为 CLIPBOARDVIEWER.DCR,并且要与
TClipBoardViewer组件放在同一个目录下。
2.发布组件组件的最大优点就是有良好的共享性,做好的组件可以由发布到网上,供大家使用。发布组件有两种方法:
( 1)发布组件及其源码将组件的包工程及组件单元文件、资源文件等全部发布,用户可以用 Delphi打开扩展名为 *.dpk包工程,然后编译安装组件即可。
( 2)只发布组件如果不想发布组件源码,则需要发布以下文件:
组件实现单元的编译结果文件( *.dcu),资源文件
( *.DCR和 *.dfm),以及包的库文件( *.bpl)和包的符号文件( *.dcp),这两个文件一般在 Delphi目录下的 Projects\bpl目录里。
11.2 典型实例练能力
11.2.1 典型实例一:支持文件拖放操作的列表框组件
【 实例题目 】
编写一个名为 TDropFileListBox的列表框组件,
该组件能够支持文件的拖放操作:当把磁盘上的磁盘文件名拖动到列表框中时,磁盘文件名将作为列表项自动添加到列表框中。
【 实现方法 】
( 1) 为实现文件拖放,涉及到三个 API函数,分别如下:
DragAcceptFiles()—— 初始化某窗口使其允许 /禁止接受文件拖放
DragQueryFile()—— 查询拖放的文件名
DragFinish()—— 释放拖放文件时使用的资源
( 2)文件拖放操作实现的基本思路如下:首先调用
DragAcceptFiles()函数初始化组件窗口,使其允许接受文件拖放,然后等待 WM_DropFiles消息(一旦用户进行了拖放文件操作,组件窗口即可获得此消息),
获得消息后即可使用 DragQueryFile()函数查询被拖放的文件名,最后调用 DragFinish()释放资源。
( 3)新组件的功能。从 TListBox为组件的基类建立组件,新组件名为:
TDropFileListBox,它比标准 TListBox增加了一个 OnDropFiles事件和一个 DropEnabled属性。
当 DropEnabled为 True时即可接受文件拖放,
文件拖放完成后激发 OnDropFiles事件,该事件提供一个 FileNames参数让用户获得文件名。
【 组件验证 】
组件安装后,创建一个项目,把该组件加载到窗体中,
可以发现该组件有一个 DropFiles事件,编写该事件的程序代码如下:
procedure TForm1.DropFileListBox1DropFiles(Sender:
TObject;
FileNames,TStringList);
begin
DropFileListBox1.Items.AddStrings(FileNames);
end;
程序的设计界面如图 11-14所示,执行程序,从磁盘上拖动几个文件到列表框中后,程序的运行界面如图 11-
15所示。
图 11-14 程序设计界面 图 11-15 程序运行界面
11.3 上机练习重应用
11.3.1 上机练习一:连续工作的按钮组件
【 练习题目 】
编写一个能够连续工作的按钮组件,当它被按下的时候,它所执行的功能就持续执行(也就是每隔一个固定的时间段执行一次按钮功能),当松开时,就停止其功能的执行。
【 组件测试 】
编译并注册组件,新建一个新的项目,在窗体上添加一个标签,一个编辑框和一个本题创建的 TButtonTimer
组件 。 程 序 的 设 计 界 面 如 图 11-16 所示 。 设置
ButtonTimer 组件的 Caption属性值为,数字增 1”,
Interval属性值为 200。 编写的的 OnPush事件代码如下:
procedure TForm1.ButtonTimer1Push(Sender,TObject);
begin
Edit1.Text,=inttostr(strtoint(Edit1.text)+1 );
end;
执行程序,按住 ButtonTimer1组件,会发现编辑框中的数字不停地加 1(每隔 0.1秒加 1),程序的运行界面如图 11-17所示。
图 11-16 程序设计界面 图 11-17 程序运行界面