




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、Delphi 除了支持使用可视化部件所见即所得地建立应用程序外,还支持为开发应用而设计 自己的部件。在本章中将阐述如何为 Delphi 应用程序编写部件。这一章将达到两个目的: 教你如何自定义部件 使你的部件成为 Delphi 环境的有机组合部分19.1 Delphi部件原理19.1.1 什么是部件部件是 Delphi 应用程序的程序构件。尽管大多数部件代表用户界面的可见元素,但部 件也可以是程序中的不可见元素, 如数据库部件。 为弄清什么是部件可以从三个方面来考察 它:功能定义、技术定义和经验定义。1. 部件的功能定义从最终用户角度, 部件是在 Component Palette上选择的,
2、并在窗体设计窗口和代码窗 口中操作的元素。 从部件编写者角度, 部件是代码中的对象。 在编写部件之前, 你应用相当 熟悉已有的 Delphi 部件,这样才能使你的部件适合用户的需要。编写部件的目标之一是使 部件尽可能的类似其它部件。2. 部件的技术定义从最简单的角度看,部件是任何从 TComponent 继承的对象。 TComponent 定义了所有部 件必须要的、 最基本的行为。 例如, 出现在 Component Palette上和在窗体设计窗口中编辑 的功能。 但是 TComponent 并不知如何处理你的部件的具体功能, 因此, 你必须自己描述它。3. 部件编写者自己的定义。在实际编程
3、中,部件是能插入 Delphi 开发环境的任何元素。它可能具有程序的各种复 杂性。 简而言之, 只要能融入部件框架, 部件就是你用代码编写的一切。 部件定义只是接口 描述, 本章将详细阐述部件框架, 说明部件的有限性, 正如说明编程的有限性。 本章不准备 教你用所给语言编写每一种部件, 只能告诉编定代码的方法和怎样使部件融入 Delphi 环境。19.1.2 编写部件的不同之处在 Delphi 环境中建立部件和在应用程序中使用部件有三个重要差别: 编写部件的过程是非可视化的 编写部件需要更深入的关于对象的知识 编写部件需要遵循更多的规则1. 编写部件是非可视化的编写部件与建立 Delphi 应
4、用最明显的区别是部件编写完全以代码的形式进行,即非可 视化的 。因为 Delphi 应用的可视化设计需要已完成的部件,而建立这些部件就需要用 Obj ect Pascal 代码编写。虽然你无法使用可视化工具来建立部件, 但你能运用 Delphi开发环境的所有编程特性 如代码编辑器、集成化调试和对象浏览。2. 编写部件需要更深的有关对象的知识除了非可视化编程之外, 建立部件和使用它们的最大区别是:当建立新部件时, 需要从 已存部件中继承产生一个新对象类型, 并增加新的属性和方法。 另一方面, 部件使用者, 在 建立 Delphi 应用时,只是使用已有部件。在设计阶段通过改变部件属性和描述响应事件
5、的 方法来定制它们的行为。当继承产生一个新对象时, 你有权访问祖先对象中对最终用户不可见的部分。 这些部分 被称为 protected 界面的。 在很大部分的实现上, 后代对象也需要调用他们的祖先对象的方 法,因此,编写部件者应相当熟悉面向对象编程特性。3. 编写部件要遵循更多的规则编写部件过程比可视化应用生成采用更传统的编程方法, 与使用已有部件相比, 有更多 的规则要遵循。在开始编写自己的部件之前,最重要的事莫过于熟练应用 Delphi 自带的部 件, 以得到对命名规则以及部件用户所期望功能等的直观认识。 部件用户期望部件做到的最 重要的事情莫过于他们在任何时候能对部件做任何事。 编写满足
6、这些期望的部件并不难, 只 要预先想到和遵循规则。19.1.3 建立部件过程概略简而言之,建立自定义部件的过程包含下列几步: 建立包含新部件的库单元 从已有部件类型中继承得到新的部件类型 增加属性、方法和事件 用 Delphi 注册部件 为部件的属性方法和事件建立 Help 文件如果完成这些工作,完整的部件包含下列 4个文件 编译的库单元 ( .DCU文件 选择板位图 (.DCR文件 Help文件 (.HLP文件 Help-keyword 文件 (.KWF文件 19.2 Delphi部件编程方法19.2.1 Delphi部件编程概述19.2.1.1 Delphi可视部件类库Delphi的部件都
7、是可视部件类库(VCL 的对象继承树的一部分,下面列出组成 VCL 的对象的关系。 TComponent 是 VCL 中每一个部件的共同祖先。 TComponent 提供了 Delphi 部件正常工作的最基本的属性和事件。库中的各条分支提供了其它的更专一的功能。当建立部件时,通过从对象树中已有的对象继承获得新对象,并将其加入 VCL 中。19.2.1.2 建立部件的起点部件是你在设计时想操作的任意程序元素。 建立新部件意味着从已有类型中继承得到新 的部件对象类。建立新部件的主要途径如下: 修改已有的控制 建立原始控制 建立图形控制 建立 Windows 控制的子类 建立非可视部件下表列出了不同
8、建立途径的起始类表 19.1 定义部件的起始点途 径 起 始 类修改已有部件 任何已有部件,如 TButton 、 TListBox或抽象部件对象如 TCustomListBox建立原始控制 TCustomControl建立图形控制 TGraphicControl建立窗口控制的子类 TWinControl建立非可视部件 TComponent也可以继承非部件的其它对象,但无法在窗体设计窗口中操作它们。 Delphi 包括许多 这种对象,如 TINIFile 、 TFont 等。1. 修改已有控制建立部件的最简单的方法是继承一个已有的、可用的部件并定制它。可以从 Delphi 提 供的任何部件中继
9、承。例如,可以改变标准控制的缺省属性值,如 TButton 。有些控制,如 Listbox 和 Grid 等有许多相同变量,在这种情况下, Delphi 提供了抽象 控制类型, 从该类型出发可定制出许多的类型。 例如, 你也许想建立 TListBox 的特殊类型, 这种部件没有标准 TListBox 的某些属性,你不能将属性从一个祖先类型中移去,因此你需 要从比 TListBox 更高层次的部件继承。例如 TCustomListBox ,该部件实现了 TCustomList Box 的所有属性但没有公布 (Publishing它们。当从一个诸如 TCustomListBox 的抽象类中 继承时
10、,你公布那些你想使之可获得的属性而让其它的保护起来 (protected。2. 建立原始控制标准控制是在运行时可见的。这些标准控制都从 TWinControl ,继承来的,当你建立原 始控制时,你使用 TCustomControl 作为起始点。标准控制的关键特征是它具有窗口句柄, 句柄保存在属性 Handle 中,这种控制: 能接受输入焦点 能将句柄传送给 Windows API函数如果控制不需要接受输入焦点,你可把它做成图形控制,这可能节省系统资源。3. 建立图形控制图形控制非常类似定制的控制, 但它们没有窗口句柄, 因此不占有系统资源。 对图形控 制最大的限制是它们不能接收输入焦点。 你需
11、要从 TGraphicControl 继承, 它提供了作图的 Canvas 和能处理 WM_PAINT消息,你需要覆盖 Paint 方法。4. 继承窗口控制Windows 中有一种称之为窗口类的概念,类似于面向对象的对象和类的概念。窗口类是 Win dows 中相同窗口或控制的不同实例之间共享的信息集合。当你用传统的 Windows 编程方法 创建一种新的控制, 你要定义一个新的窗口类, 并在 Windows 中注册。 你也能基于已有的窗 口类创建新的窗口类。 这就称为从窗口类继承。 在传统的 Windows 编程中, 如果你想建立客 户化的控制, 你就必须将其做在动态链接库里, 就象标准 W
12、indows 控制, 并且提供一个访问 界面。使用 Delphi ,你能创建一个部件包装在已有窗口类之上。如果你已有客户化控制的 库,并想使其运行在你的 Delphi 应用中,那你就能创建一个使你能使用已有控制和获得新 的控制的部件。在库单元 StdCtrls 中有许多这样的例子。5. 建立非可视化的部件抽象对象类型 TComponent 是所有部件的基础类型。 从 TComponent 直接继承所创建的部 件就是非可视化部件。你编写的大多数部件都是可视控制。 TComponent 定义了部件在 Form Designer 中所需的基本的属性和方法。因此, 从 TComponent 继承来的任
13、何部件都具备设计 能力。非可视部件相当少, 主要用它们作为非可视程序单元 (如数据库单元 和对话框的界面。 19.2.1.3 建立新部件的方法建立新部件的方法有两种: 手工建立部件 使用 Component Expert一旦完成建立后,就得到所需的最小功能单位的部件,并可以安装在 Component Palette上。 安装完后, 你就能将新部件放置在窗体窗口, 并可在设计阶段和运行阶段进行测试。 你 还能为部件增加新的特征、更新选择板、重新测试。1. 手工创建部件显然创建部件最容易的方法是使用 Component Expert。然而,你也能通过手工来完成相同 步骤。手工创建部件需要下列三步:
14、 创建新的库单元 继承一个部件对象 注册部件 创建新的库单元库单元是 Object Pascal代码的独立编译单位。 每一个窗体有自己的库单元。 大多数部 件(在逻辑上是一组也有自己的库单元。当你建立部件时, 你可以为部件创建一个库单元, 也可将新的部件加在已有的库单元中。 为部件创建库单元,可选择 File/New. ,在 New Items对话框中选择 Unit , Delph i 将创建一个新文件,并在代码编辑器中打开它 在已有库单元中增加部件,只须选择 File/OPen为已有库单元选择源代码。在该库单 元中只能包含部件代码,如果该库单元中有一个窗体,将产生错误 继承一个部件对象每个部
15、件都是 TComponent 的后代对象。也可从 TControl 、 TGraphicControl 等继承。 为继承一个部件对象,要将对象类型声明加在库单元的 interface 部分。例如,建立一个最简单的从 TComponent 直接继承非可视的部件,将下列的类型定义加 在部件单元的 interface 部分。typeTNewComponent=class(TComponentend;现在你能注册 TNewComponent 。但是新部件与 TComponent 没什么不同,你只创建了自己 部件的框架。 注册部件注册部件是为了告诉 Delphi 什么部件被加入部件库和加入 Compon
16、ent Palette的哪一 页。为了注册一个部件: 在部件单元的 interface 部分增加一个 Register 过程。 Register 不带任何参数, 因此声明很简单:procedure Register;如果你在已有部件的库单元中增加部件,因为已有 Register 过程,因此不须要修改声明。 在库单位的 implementation 部件编写 Register 过程为每一个你想注册的部件调用 过程 RegisterComponents ,过程 RegisterComponents 带两个参数:Component Palette的 页名和部件类型集。例如,注册名为 TNewComp
17、onent 的部件,并将其置于 Component Palet te 的 Samples 页,在程序中使用下列过程:procedure Register;beginRegisterComponents('Samples', TNewComponent;end;一旦注册完毕, Delphi 自动将部件图标显示在 Component Palette上。2. 使用 Component Expert(部件专家你能使用 Component Expert创建新部件。 使用 Component Expert简化了创建新部件最 初阶段的工作,因为你只需描述三件事: 新部件的名字 祖先类型 新部
18、件要加入的 Component Palette页名Component Expert执行了手工方式的相同工作: 建立新的库单元 继承得到新部件对象 注册部件但 Component Expert不能在已有单元中增加部件。可选择 File/New. ,在 New Items对话框中选择 Component ,就打开 Component Expert对话框。填完 Component Expert对话框的每一个域后,选择 OK 。 Delphi 建立包括新部件和 Reg ister 过程的库单元,并自动增加 uses 语句。你应该立刻保存库单元,并给予其有意义的名字。19.2.1.4. 测试未安装的部件
19、在将新部件安装在 Component Palette之前就能测试部件运行时的动作。 这对于调试新 部件特别有用,而且还能用同样的技术测试任意部件,无论该部件是否出现在 Component P alette 上。从本质上说, 你通过模仿用户将部件放置在窗体中的 Delphi 的动作来测试一个未安装的 部件。可按下列步骤来测试未安装的部件1. 在窗体单元的 uses 语句中加入部件所在单元的名字2. 在窗体中增加一个对象域来表示部件这是自己增加部件和 Delphi 增加部件的方法的主要不同点。你将对象域加在窗体类型声明底部的 public 部分。 Delphi 则会将对象域加在底部声明 的上面。你
20、不能将域加在 Delphi 管理的窗体类型的声明的上部。在这一部分声明的对象域将相 应在存储在 DFM 文件中。增加不在窗体中存在的部件名将产生 DFM 文件无效的错误。3. 附上窗体的 OnCreate 事件处理过程4. 在窗体的 OnCreate 处理过程中构造该部件当调用部件的构造过程时, 必须传递 Owner 参数 (由 Owner 负责析构该部件 一般说来 总是将 Self 作为 Owner 的传入参数。在 OnCreate 中, Self 是指窗体。5. 给 Component 的 Parent 属性赋值设置 Parent 属性往往是构造部件后要做的第一件事时。 Parent 在形
21、式上包含部件,一 般来说 Parent 是窗体或者 GoupBox 、 Panel 。通常给 Parent 赋与 Self ,即窗体。在设置部 件的其它属性之前最好先给 Parent 赋值。6. 按需要给部件的其它属性赋值假设你想测试名为 TNewComponent 类型的新部件,库单元名为 NewTest 。窗体库单元应 该是这样的;unit Unitl;interfaceuses SysUtils, Windows, Messages, Classes, Grophics, Controls, Forms, Dialogs, Newtest;typeTforml = class(TForm
22、procedure FormCreate(Sender: TObject;private private申 明 public public申 明 NewComponent: TNewComponent;end;varForml: TForml;implementation$R *.DFM procedure TForml.FormCreate ( Sender: TObject ;beginNewComponent := TNewComponent.Create ( Self ;NewCompanent.Parent := Self;NewCompanent.Left := 12;end;en
23、d.19.2.1.5 编写部件的面向对象技术部件使用者在 Delphi 环境中开发,将遇到在包含数据和方法的对象。他们将在设计阶 段和运行阶段操作对象, 而编写部件将比他们需要更多的关于对象的知识, 因此, 你应当熟 悉 Delphi 的面向对象的程序设计。1. 建立部件部件用户和部件编写者最基本的区别是用户处理对象的实例, 而编写者创建新的对象类 型。 这个概念是面向对象程序设计的基础。 例如, 用户创建了一个包含两个按钮的窗体, 一 个标为 OK ,另一个标为 Cancel ,每个都是 TButton 的实例,通过给 Text 、 default 和 Canc el 等属性赋不同的值,给
24、OnClick 事件赋予不同的处理过程,用户产生了两个不同的实例。建立新部件一般有两个理由 改变类型的缺省情况,避免反复 为部件增加新的功能目的都是为了建立可重用对象。 如果从将来重用的角度预先计划和设计, 能节省一大堆 将来的工作。在程序设计中, 避免不必要的重复是很重要的。 如果发现在代码中一遍又一遍重写相同 的行,就应当考虑将代码放在子过程或函数中,或干脆建立一个函数库。设计部件也是这个道理, 如果总是改变相同的属性或相同的方法调用, 那应创建新部件。创建新部件的另一个原因是想给已有的部件增加新的功能。 你可以从已有部件直接继承 (如 ListBox 或从抽象对象类型继承(如 TComp
25、onent , TControl 。你虽然能为部件增加 新功能, 但不能将原有部件的属性移走, 如果要这样做的话, 就从该父对象的祖先对象继承。2. 控制部件的访向Object Pascal语言为对象的各部分提供了四个级别的访问控制。 访问控制让你定义什 么代码能访问对象的哪一部分。 通过描述访问级别, 定义了部件的接口。 如果合理安排接口, 将提高部件的可用性和重用性。除非特地描述,否则加在对象里的域、方法和属性的控制级别是 published ,这意味着 任何代码可以访问整个对象。下表列出各保护级别:表 19.2 对象定义中的保护级别保护级 用处private 隐藏实现细节protecte
26、d 定义开发者接口public 定义运行时接口published 定义设计时接口所有的保护级都在单元级起作用。 如果对象的某一部分在库单元中的一处可访向, 则在该库 单元任意处都可访向。 隐藏实现细节如果对象的某部分被声明为 private ,将使其它库单元的代码无法访问该部分,但包含 声明的库单元中的代码可以访问,就好象访问 public 一样,这是和 C+不同的。对象类型的 private 部分对于隐藏详细实现是很重要的。既然对象的用户不能访问, p rivate 部分,你就能改变对象的实现而不影响用户代码。下面是一个演示防止用户访问 private 域的例子:unit HideInfo;
27、interfaceuses SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls, Forms, Dialogs;typeTSecretForm = class(TForm 声明新的窗体窗口 procedure FormCreate(Sender: TObject;private declare private part FSecretCode: Integer; 声明 private 域 end;varSecretForm: TSecretForm;implementationprocedure TSecret
28、Form.FormCreate(Sender: TObject;beginFSecretCode := 42;end;end.unit TestHide; 这是主窗体库单元 interfaceuses SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls, Form s,Dialogs, HideInfo; 使用带 TSecretForm 声明的库单元 typeTTestForm = class(TFormprocedure FormCreate(Sender: TObject;end;varTestForm:
29、TTestForm;implementationprocedure TTestForm.FormCreate(Sender: TObject;beginSecretForm.FSecretCode := 13; 编译过程将以 "Field identifier expected"错误停止 end;end. 定义开发者接口将对象某部分声明为 protected ,可使在包含该部件声明的库单元之外的代码无法访 问,就象 private 部分。 protected 部分的不同之处是,某对象继承该对象,则包含新对象 的库单元可以访问 protected 部分, 你能使用 prote
30、cted 声明定义开发者的接口。 也就是说。 对象的用户不能访向 protected 部分,但开发者通过继承就可能做到,这意味着你能通过 p rotected 部分的可访问性使部件编写者改变对象工作方式,而又不使用户见到这些细节。 定义运行时接口将对象的某一部分定义为 public 可使任何代码访问该部分。如果你没有对域方法或属 性加以 private 、 protected 、 public 的访问控制描述。那么该部分就是 published 。因为对象的 public 部分可在运行时为任何代码访问, 因此对象的 public 部分被称为运 行接口。运行时接口对那些在设计时没有意义的项目,如
31、依靠运行时信息的和只读的属性, 是很有用的。那些设计用来供用户调用的方法也应放在运行时接口中。下例是一个显示两个定义在运行时接口的只读属性的例子:typeTSampleComponent = class(TComponentprivateFTempCelsius: Integer; 具体实现是 private function GetTempFahrenheit: Integer;publicproperty TempCelsius: Integer read FTempCelsius; 属性是 public property TempFahrenheit: Integer read GetT
32、empFahrenheit;end;function GetTempFahrenheit: Integer;beginResult := FTempCelsius * 9 div 5 + 32;end;既然用户在设计时不能改变 public 部分的属性的值, 那么该类属性就不能出现在 Object I nspector 窗口中。 定义设计时接口将对象的某部分声明为 published ,该部分也即为 public 且产生运行时类型信息。但 只有 published 部分定义的属性可显示在 Object Inspector窗口中。对象的 published 部 分定义了对象的设计时接口。设计时接
33、口包含了用户想在设计时定制的一切特征。下面是一个 published 属性的例子,因为它是 published ,因此可以出现在 Object In spector 窗口:TSampleComponent = class(TComponentprivateFTemperature: Integer; 具体实现是 private publishedproperty Temperature: Integer read FTemperature write FTemperature; 可写的 end;3. 派送方法派送 (Dispatch这个概念是用来描述当调用方法时, 你的应用程序怎样决定执行什么
34、样 的代码, 当你编写调用对象的代码时, 看上去与任何其它过程或函数调用没什么不同, 但对 象有三种不同的派送方法的方式。这三种派送方法的类型是: 静态的 虚拟的 动态的虚方法和动态方法的工作方式相同, 但实现不同。 两者都与静态方法相当不同。 理解各 种不同的派送方法对创建部件是很有用的。 静态方法:如果没有特殊声明,所有的对象方法都是静态的 . 。静态方法的工作方式正如一般的过 程和函数调用。在编译时,编译器决定方法地址,并与方法联接。静态方法的基本好处是派送相当快。 因为由编译器决定方法的临时地址, 并直接与方法 相联。 虚方法和动态方法则相反, 用间接的方法在运行时查找方法的地址, 这
35、将花较长的时 间。静态方法的另一个不同之处是当被另一类型继承时不做任何改变, 这就是说如果你声明 了一个包含静态方法的对象, 然后从该对象继承新的对象, 则该后代对象享有与祖先对象相 同的方法地址,因此,不管实际对象是谁,静态方法都完成相同的工作。你不能覆盖静态方法,在后代对象中声明相同名称的静态方法都将取代祖先对象方法。在下列代码中, 第一个部件声明了两静态方法, 第二个部件, 声明了相同名字的方法取 代第一个部件的方法。typeTFirstComponent = class(TComponentprocedure Move;procedure Flash;end;TSecondComponent = class(TFirstComponentprocedure Move; 尽管有相同的声明,但与继承的方法不同 function Flash(HowOften: Integer: Integer; 同 Move 方法一样 end; 虚方法调用虚方法与调用任何其它方法一样, 但派送机制有所不同。 虚方法支持在后代对象中 重定义方法, 但调
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024-2025学年高中数学课时分层作业3排列的应用含解析北师大版选修2-3
- 2024-2025学年高中生物第1章无菌操作技术实践第1节微生物的分离和培养学案苏教版选修1
- 2024-2025学年高中英语Unit5InsideadvertisingSectionⅡLanguagePoints讲义新人教版选修9
- 2024-2025学年高中历史专题5欧洲宗教改革1“神圣的中心组织”-天主教练习人民版选修1
- 2024-2025学年高中物理第1章3平抛运动第1课时平抛运动的特点及规律练习含解析教科版必修2
- 2022-2027年中国旅游景区市场竞争格局及未来投资前景预测报告
- 2024年河北省普通高中学业水平选择性考试物理试题含答案
- 2024-2030年辽宁塔吊租赁行业发展研究与前景分析报告
- 2020-2025年中国热饮料包装市场运行态势及行业发展前景预测报告
- 2024年软件外包项目可行性研究报告
- 2021年陕西西安亮丽电力集团有限责任公司招聘笔试试题
- 高中英语-Studying abroad教学课件设计
- 原材料取样检测安全操作规程
- 创新思维与方法(第2版)PPT全套完整教学课件
- (5.3.2)-2.2杂草的分类农田杂草及防除学
- 人教部编道德与法治五年级下册单元计划
- 天津武清区事业单位考试真题2022
- 铁路营业线施工安全管理培训课件
- 旅行社运营实务电子课件 1.2 了解旅行社核心业务部门
- 综合交通运输体系认知
- GM/T 0115-2021信息系统密码应用测评要求
评论
0/150
提交评论