8.4 Delphi自定义组件(3)

 

3. 测试未安装的组件

在将新组件安装在Component Palette之前就能测试组件运行时的动作。这对于调试新组件特别有用,而且还能用同样的技术测试任意组件,无论该组件是否出现在Component Palette上。

从本质上说,可通过模仿用户将组件放置在Delphi窗体中的动作来测试一个未安装的组件。可按下列步骤来测试未安装的组件:

(1)在窗体单元的uses语句中加入组件所在单元的名字。

(2)在窗体中增加一个对象域来表示组件。

(3)附上窗体的OnCreate事件处理过程。

(4)在窗体的OnCreate事件处理过程中构造该组件。

当调用组件的构造过程时,必须传递Owner参数(由Owner负责析构该组件)。一般说来,总是将Self作为Owner的传入参数。在OnCreate中,Self是指窗体自身。

(5)给Component的Parent属性赋值。

设置Parent属性是构造组件后要做的第一件事。Parent在形式上包含组件,一般来说,Parent是窗体或者GroupBox、Panel等。通常给Parent赋值为Self,即窗体。在设置组件的其他属性之前最好先给Parent赋值。

(6)按需要给组件的其他属性赋值。

假设你想测试名为TNewComponent类型的新组件,单元名为NewTest。窗体单元应该是这样的:

unit Unitl;

interface

uses SysUtils, Windows, Messages, Classes, Grophics, Controls,

Forms,Dialogs, Newtest;

type

Tforml = class(TForm)

procedure FormCreate(Sender: TObject);

private

{ private声 明 }

public

{ public声 明 }

NewComponent: TNewComponent;

end;

var

Forml: TForml;

implementation

{$R *.DFM }

procedure TForml.FormCreate ( Sender: TObject ) ;

begin

NewComponent := TNewComponent.Create ( Self );

NewCompanent.Parent := Self;

NewCompanent.Left := 12;

end;

end.

现在这个新建的组件已经添加到我们的测试单元中,而且有了一个实例。我们可以在测试单元的其他部分利用这个实例来检测组件的相关功能。

8.4.4 组件功能设计

在8.4.3节,我们已经可以搭建组件的完整框架,但是为了实现预期中组件的最终功能,还需要为组件实现相应的属性和方法。下面就进行详细的介绍。

1. 创建属性

在前面的章节,我们已经简要地介绍了组件的属性(Property)。

属性是组件中最特殊的部分,这主要是因为组件用户在设计时可以看见和操作它们,并且在交互过程中能立即得到返回结果。属性也很重要,因为如果它们设计合理,用户使用起来将更容易,维护起来也更方便。

为了在组件中更好地使用属性,本节将介绍下列内容。

(1)为什么要创建属性

属性提供非常重要的好处,最明显的好处是属性在设计时能出现在Object Inspector窗口中,这将简化编程工作。因为你只需读取用户所赋的值,而不要处理构造对象的参数。

从组件用户的观点看,属性像变量。用户可以给属性赋值或读取属性的值,就好像属性是对象的域。

从组件编写者的观点看,属性比对象的域有更强的功能:

1)用户可以在设计时设置属性。这是非常重要的,因为不像方法,只能在运行时访问。属性使用户在运行程序之前就能定制组件,通常用户的组件不应包含很多的方法,它们的功能可以通过属性来实现。

2)属性能隐藏详细的实现细节。

3)属性能引起简单地赋值之外的响应,如触发事件。

4)用于属性的实现方法可以是虚拟方法,这样看似简单的属性在不同的组件中将实现不同的功能。

(2)属性的类型

属性可以是函数能返回的任何类型,因为属性的实现可以使用函数。所有的Pascal类型和兼容性规则都适用于属性。为属性选择类型的最重要的方面是,不同的类型出现在Object Inspector窗口中的方式不同。Object Inspector将按类型的不同决定其出现的方式。

表8.2列出属性出现在Object Inspector窗口中的方式。

表8.2 属性出现在Object Inspector窗口中的方式

属性类型

处理方式

简单类型

Numeric、Character和 String属性出现在Object Inspector中,用户可以直接编辑

枚举类型

枚举类型的属性显示值的方式定义在代码中。选择时将出现下拉列表框,显示所有的可能取值

集合类型

集合类型出现在Object Inspector窗口中时正如一个集合,展开后,用户通过将集合元素设为True或False来选择

属性类型

处理方式

对象类型

作为对象的属性本身有属性编辑器,如果对象有自己的Published属性,用户在Object Inspector中通过展开对象属性列,可以独立编辑它们。对象类型的属性必须从TPersistent继承

数组类型

数组属性必须有它们自己的属性编辑器,Object Inspector没有内嵌对数组属性编辑的支持

(3)重定义继承的属性为Published

所有组件都从祖先类型继承属性。当你从已有组件继承时,新组件将继承祖先类型的所有属性。如果继承的是抽象类,则继承的属性是Protected或Public,但不是Published。如想使用户访问Protected或Public属性,可以将该属性重定义为Published。如果你使用TWinControl继承,它继承了Ctl3D属性,但是因为是Protected性质的,所以用户在设计和运行时不能访问Ctl3D。通过在新组件中将Ctl3D重声明为Published,就改变了Ctl3D的访问级别。

(4)定义组件属性

1)属性的声明

声明组件的属性,你要描述:

· 属性名

· 属性的类型

· 读和设置属性值的方法

至少,组件属性应当定义在组件对象声明的Public部分,这样可以在运行时很方便地从外部访问。为了能在设计时编辑属性,应当将属性在Published部分声明,这样属性能自动显示在Object Inspector窗口中。

2)内部数据存储

关于如何存储属性的数据值,Delphi没有特别的规定,通常Delphi组件遵循下列规定:

· 属性数据存储在对象的数据域处。

· 属性对象域的标识符以F开头,例如定义在TControl中的FHeigh属性。

· 属性数据的对象域应声明在Private部分。

后代组件只应使用继承的属性自身,而不能直接访问内部的数据存储。

3)直接访问

使属性数据可用的最简单的办法是直接访问。如果在属性声明的read和write部分直接赋值给属性数据,则对象调用时不通过访问方法而是直接读出和写入内部数据域。为了数据安全起见,一般都用read进行直接属性访问,而用write进行方法访问,以改变组件的状态。

下面就是一个典型的属性声明:

private

FFrameColor: TColor;

published

property FrameColor: TColor read FFrameColor write SetFrameColor;

4)访问方法

属性的声明语法允许属性声明的read和write部分用访问方法取代对象私有数据域。不管属性是如何实现它的read和write部分,方法实现应当是Private,后代组件只能使用继承的属性访问。

5)读方法

属性的读方法是不带参数的函数,并且返回同属性相同类型的值。通常读函数的名字是Get后加属性名。例如,属性Count的读方法是GetCount。不带参数的惟一例外是数组属性。如果你不定义read方法,则属性是只写的。

6)写方法

属性的写方法总是只带一个参数的过程。参数可以是引用参数或值参数。通常过程名是Set加属性名。例如,属性Count的写方法名是SetCount。参数的值采用设置属性的新值,因此,写方法需要执行在内部存储数据中写的操作。

如果没有声明写方法,那么属性是只读的。

通常在设置新值前要检测新值是否与当前值不同。

7)默认属性值

当声明一个属性时,能有选择地声明属性的默认值。组件属性的默认值是组件构造方法中的属性值集。例如,当从Component Palette选择某组件置于窗体中时,Delphi通过调用组件构造方法创建组件,并决定组件属性初始值。

Delphi使用声明默认值决定是否将属性值存在DFM文件中。如果不描述默认值,Delphi将总是保存该属性值。声明默认值的方法是在属性声明后加default指令,再跟默认值。

当重声明一个属性时,能够描述没有默认值的属性。如果继承的属性已有一个,则设立没有默认值的属性的方法是在属性声明后加nodefault指令。如果是第一次声明属性,则没有必要加nodefault指令。

参考:

http://tech.163.com/06/0429/11/2FSGE5HL00091SD5.html
http://tech.163.com/06/0429/11/2FSGHQJR00091SD5.html
http://tech.163.com/06/0429/11/2FSGKDBR00091SD5.html
http://tech.163.com/06/0429/11/2FSGLRNL00091SD5.html
http://tech.163.com/06/0429/11/2FSGOOKO00091SD5.html

http://hi.baidu.com/avatee/item/e60091b5c8732d921846977b

http://www.cnblogs.com/del/archive/2008/01/18/1044301.html

Delphi属性比对象的域有更强的功能的更多相关文章

  1. ApplicationContext更强的功能-学习笔记

    ---恢复内容开始--- 一.国际化支持 二.资源访问 三.事件传递 国际化支持 ApplicationContext继承了org.springframework.context.MessageRes ...

  2. Delphi引用C对象文件

    C语言应用非常广泛,并在世界各地拥有大量的代码库.这些代码库与Delphi的可比性较小,因此如果我们无需转换为Delphi代码而可以直接使用这些库的部分代码就完美了.幸运的是,Delphi允许连接到C ...

  3. Delphi引用C对象文件(转)

    源:http://blog.csdn.net/henreash/article/details/7357618 C语言应用非常广泛,并在世界各地拥有大量的代码库.这些代码库与Delphi的可比性较小, ...

  4. C#高级知识点概要(3) - 特性、自动属性、对象集合初始化器、扩展方法、Lambda表达式和Linq查询

    1.特性(Attributes) 特性(Attributes),MSDN的定义是:公共语言运行时允许你添加类似关键字的描述声明,叫做attributes, 它对程序中的元素进行标注,如类型.字段.方法 ...

  5. ios中属性和对象的初始化

    属性和对象的初始化为了方便记忆, 我们可以都使用self.来初始化. 这样可以避免内存的过度释放.

  6. 007-Scala类的属性和对象私有字段实战详解

    007-Scala类的属性和对象私有字段实战详解 Scala类的使用实战 变量里的类必须赋初值 def函数时如果没参数可不带括号 2.不需要加Public声明 getter与setter实战 gett ...

  7. javascript 获取调用属性的对象

    最近碰到一个javascript 的小问题,是和闭包有关的,来自cnode 论坛,很有意思. var o = (function() { var person = { name: 'Vincent', ...

  8. C++类继承中,基类/当前对象属性/当前对象的构造顺序

    [1]中提到,规范的派生类构造函数三个要点: 首先创建基类对象 应通过成员初始化列表,创建基类对象 应该初始化本派生类新增的成员变量 那在构造派生类实例的过程中,其基类(以及多继承的时候多个基类)/当 ...

  9. Python笔记(七):字典、类、属性、对象实例、继承

    (一)  简单说明 字典是Python的内置数据结构,将数据与键关联(例如:姓名:张三,姓名是键,张三就是数据).例如:下面这个就是一个字典 {'姓名': '张三', '出生日期': '2899-08 ...

随机推荐

  1. 阿里云部署flask

    https://www.cnblogs.com/Ray-liang/p/4173923.html

  2. js 页面图片等元素在普通元素中滚动动态加载技术

    /*! * 2012-01-13 v1.1 偏移值计算修改 position → offset * 2012-09-25 v1.2 增加滚动容器参数, 回调参数 * 2015-11-17 v1.3 只 ...

  3. 3D超炫酷旋转

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  4. 在你的Android手机上运行Linux

    之前试过许多方法(也就几种),像什么Complete Linux Installer,Debian noroot,利用已有的Linux构造Bootstrap之类,要么就是复杂得要命(调了两天没有调出来 ...

  5. IO之转换流举例

    import java.io.*; public class TestTransForm1 { public static void main(String[] args) { try { Outpu ...

  6. [Python3网络爬虫开发实战] 4-解析库的使用

    上一章中,我们实现了一个最基本的爬虫,但提取页面信息时使用的是正则表达式,这还是比较烦琐,而且万一有地方写错了,可能导致匹配失败,所以使用正则表达式提取页面信息多多少少还是有些不方便. 对于网页的节点 ...

  7. Python:用户自定义异常

    实际开发中,有时候系统提供的异常类型不能满足开发的需求.这时候你可以通过创建一个新的异常类来拥有自己的异常.异常类继承自 Exception 类,可以直接继承,或者间接继承. 1.自定义异常类型 #1 ...

  8. Python之机器学习-朴素贝叶斯(垃圾邮件分类)

    目录 朴素贝叶斯(垃圾邮件分类) 邮箱训练集下载地址 模块导入 文本预处理 遍历邮件 训练模型 测试模型 朴素贝叶斯(垃圾邮件分类) 邮箱训练集下载地址 邮箱训练集可以加我微信:nickchen121 ...

  9. table中JS选取行列

    <table border="1" align="center" style="width: 500px" id="doct ...

  10. 【BZOJ 1003】[ZJOI2006]物流运输(Dijkstra+DP)

    题链 http://www.lydsy.com/JudgeOnline/problem.php?id=1003 Description 物流公司要把一批货物从码头A运到码头B.由于货物量比较大,需要n ...