19.2.2 Delphi部件编程 19.2.2.1 创建属性 属性(Property)是部件中最特殊的部分,主要因为部件用户在设计时可以看见和操作它们,并且在交互过程中能立即得到返回结果。属性也很重要,因为如果将它们设计好后,将使用户更容易地使用,自己维护起来也很容易。 为了使你在部件中更好地使用属性,本部分将介绍下列内容: ● 为什么要创建属性 ● 属性的种类 ● 公布(publishing)继承的属性 ● 定义部件属性 ● 编写属性编辑器 1. 为什么要创建属性 属性提供非常重要的好处,最明显的好处是属性在设计时能出现在Object Inspector窗口中,这将简化编程工作,因为你只需读用户所赋的值,而不要处理构造对象的参数。 从部件使用者的观点看,属性象变量。用户可以给属性赋值或读值,就好象属性是对象的域。 从部件编写者的观点看属性比对象的域有更强的功能; ⑴ 用户可以在设计时设置属性 这是非常重要的,因为不象方法,只能在运行时访问。属性使用户在运行程序之前就能定制部件,通常你的部件不应包含很多的方法,它们的功能可以通过属性来实现。 ⑵ 属性能隐藏详细的实现细节 ⑶ 属性能引起简单地赋值之外的响应,如触发事件 ⑷ 用于属性的实现方法可以是虚拟方法,这样看似简单的属性在不同的部件中,将实现不同的功能。 2. 属性的类型 属性可以是函数能返回的任何类型,因为属性的实现可以使用函数。所有的Pascal类型,兼容性规则都适用属性。为属性选择类型的最重要的方面是不同的类型出现在Object Inspector窗口中的方式不同。Object Inspector将按不同的类型决定其出现的方式。 你也能在注册部件时描述不同的属性编辑器。 下表列出属性出现在Object Inspector窗口中的方式 表19.3 属性出现在Object Inspector窗口中的方式 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 属性类型 处 理 方 式 ─────────────────────────────────────── 简单类型 Numeric、Character和 String属性出现在Object Inspector中,用户可 以直接编辑 枚举类型 枚举类型的属性显示值的方式定义在代码中。选择时将出现下拉 式列表框,显示所有的可能取值。 集合类型 集合类型出现在Object Inspector窗口中时正如一个集合,展开后,用 户通过将集合元素设为True或False来选择。 对象类型 作为对象的属性本身有属性编辑器,如果对象有自己的published属 性,用户在Object Inspector中通过展开对象属性列,可以独立编辑它们, 对象类型的属性必须从TPersistent继承。 数组类型 数组属性必须有它们自己的属性编辑器,Object Inspector没有内嵌对数 组属性编辑的支持。 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3. 公布继承的属性 所有部件都从祖先类型继承属性。当你从已有部件继承时,新部件将继承祖先类型的所有属性。如果你继承的是抽象类,则继承的属性是protected或public,但不是published。如想使用户访问protected或public属性,可以将该属性重定义为published。如果你使用TWinControl继承,它继承了Ctl3D属性,但是protected的,因此用户在设计和运行时不能访问Ctl3D,通过在新部件中将Ctl3D重声明为published,就改变了Ctl3D的访问级别。下面的代码演示如何将Ctl3D声明为published,使之在设计时可被访问。 type TSampleComponent=class(TWinControl) published property Ctl3D; end; 4. 定义部件属性 ⑴ 属性的声明 声明部件的属性,你要描述: ● 属性名 ● 属性的类型 ● 读和设置属性值的方法 至少,部件属性应当定义在部件对象声明的public部分,这样可以在运行时很方便地从外部访问;为了能在设计时编辑属性,应当将属性在published部分声明,这样属性能自动显示在Object Inspector窗口中。下面是典型的属性声明: type TYourComponent=class(TComponent) … private FCount: Integer { 内部存储域 } function GetCount: Integer; { 读方法 } procedure SetCount(ACount: Integer); { 写方法 } pubilic property Count: Integer read GetCount write SetCount; end; ⑵ 内部数据存储 关于如何存储属性的数据值,Delphi没有特别的规定,通常Delphi部件遵循下列规定: ● 属性数据存储在对象的数据域处 ● 属性对象域的标识符以F开头,例如定义在TControl中的属性FWidth ● 属性数据的对象域应声明在private部分 后代部件只应使用继承的属性自身,而不能直接访问内部的数据存储。 ⑶ 直接访问 使属性数据可用的最简单的办法是直接访问。属性声明的read 和write部分描述了怎样不通过调用访问方法来给内部数据域赋值。但一般都用read进行直接访问,而用write进行方法访问,以改变部件的状态。 下面的部件声明演示了怎样在属性定义的read 和write部分都采用直接访问: type TYourComponent=class(TComponent) … private { 内部存储是私有 } FReadOnly: Boolean; { 声明保存属性值的域 } published { 使属性在设计时可用 } property ReadOnly: Boolean read FReadOnly write FReadOnly; end; ⑷ 访问方法 属性的声明语法允许属性声明的read和write部分用访问方法取代对象私有数据域。不管属性是如何实现它的read 和write部分,方法实现应当是private,后代部件只能使用继承的属性访问。 ① 读方法 属性的读方法是不带参数的函数,并且返回同属性相同类型的值。通常读函数的名字是“Get”后加属性名,例如,属性Count的读方法是GetCount。不带参数的唯一例外是数组属性。如果你不定义read方法,则属性是只写的。 ② 写方法 属性的写方法总是只带一个参数的过程。参数可以是引用或值。通常过程名是"Set"加属性名。例如,属性Count的写方法名是SetCount。参数的值采用设置属性的新值,因此,写方法需要执行在内部存储数据中写的操作。 如果没有声明写方法,那么属性是只读的。 通常在设置新值前要检测新值是否与当前值不同。 下面是一个简单的整数属性Count的写方法: procedure TMyComponent.SetCount( value: Integer); begin if value <>FCount then begin FCount := Value; update; end; end; <  
1/2 1 2 下一页 尾页 |