分享
 
 
 

Delphi组件属性

王朝delphi·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

Delphi组件属性

作者:邹飞

E-mail:zouf.tech@ATechSoft.com

Homepage:http://www.atechsoft.com/people/zouf/

注:本文讨论对于Delphi中自定义控件(User-Defined Controls)中的属性问题,而且主要是讨论设计时(In-Design)的属性问题,即控件在Delphi的Object Inspector中看到的属性。本文将对如何实现这些属性进行较详细的说明。

简单属性

熟悉Object Pascal的人都知道,要使控件在Object Inspector中显示出属性,只需在类的published中增加相应的property即可。下面给出一个最简单的例子,它将在Standard面板中注册一个简单的控件,这个控件只有一个自定义属性(Caption: string):

TA = class(TWinControl)

private

FCaption: string;

published

property Caption: string read FCaption write FCaption;

end;

procedure Register;

procedure Register;

begin

RegisterComponents('Standard', [TOutlookPnl]);

end;

对象属性

如果一个类的属性为对象,在Object Inspector中将会显示成如下的样式,

图中红色标出的属性:Action是一个对象属性(类型为TBaseAction),Delphi在设计时会自动从当前窗体中找出类型与之向上兼容的对象,并列出于下拉列表中(如上图的Action1、Action2、Action3…)

这种属性的实现和简单属性的实现没有什么区别,也是在published中的property中定义即可:

property Action: TBaseAction read FAction write FAction;

List型属性

Delphi中的TListView中的Columns属性、DBGrids中的Columns属性等,它们在Object Inspector中显示的是:

点击右边的“…”按钮会打开如下的窗体:

用户可以在设计时在该窗体中点右键“Add”新的项(item)。

这种类型的属性的本质在于:它的取值为一个Collection,用户可以在弹出的窗体中设计这个Collection中的具体内容。

下面以一个例子来介绍如何实现这种类型的属性:

Unit A;

interface

uses Classes, Windows, SysUtils, Controls;

type

TListProps = class; // 这个类是用于表示该List属性的集合类型

TA = class(TWinControl)

private

FListProps: TListProps;

published

property ListProps: TListProps read FListProps write FListProps; // List属性

public

constructor Create(AOwner: TComponent); override; 这里先创建List属性

destructor Destroy; override; // 记得销毁List属性

end;

// List属性中的Item类型,实际上一个List属性就是一个Collection,而其中的Item的类型必须继承自TCollectionItem

TListItem = class(TCollectionItem)

private

FItem: TWinControl;

public

procedure Assign(Source: TPersistent); override; // 因为需要进行赋值操作,必须重载该方法,将数据域进行copy

published

property Item: TWinControl read FItem write FItem; // 这里如上图中的TListColumn的属性

end;

// List集合类

TListProps = class(TCollection)

private

FOwner: TPersistent; // 这个属性是必须的,因为对于List属性,如果在设计时在弹出的窗口中进行了编辑,必须将修改的结果反应到原始控件中,这里通过这个属性表明了List属性的所有者(Owner),这样在List属性被修改时可以通知Owner作出相应调整,与之相应的,一般在这个类里还需要重载:procedure Update(Item: TCollectionItem); override;这个方法

protected

function GetOwner: TPersistent; override;

public

constructor Create(AOwner: TPersistent);

function Owner: TPersistent;

end;

procedure Register;

implementation

procedure Register;

begin

RegisterComponents('Standard', [TA]);

end;

{ TListItem }

procedure TListItem.Assign(Source: TPersistent);

begin

inherited;

if Source is TListItem then

begin

FItem := TListItem(Source).FItem;

end

else inherited Assign(Source);

end;

{ TListProps }

constructor TListProps.Create(AOwner: TPersistent);

begin

inherited Create(TListItem);

FOwner := AOwner;

end;

function TListProps.GetOwner: TPersistent;

begin

Result := FOwner;

end;

function TListProps.Owner: TPersistent;

begin

Result := FOwner;

end;

{ TA }

constructor TA.Create(AOwner: TComponent);

begin

inherited;

FListProps := TListProps.Create(Self);

end;

destructor TA.Destroy;

begin

FreeAndNil(FListProps);

inherited;

end;

end.

其它部分的理解都是很简单的,这里关键的是集合类TListProps的实现,包括其中Owner、Update等的实现策略都是要好好领会的。

当然这里只是一个最基本的框架,实际的控件可能还需要增加一些东西。

自定义属性

还有最后一种类型的“属性”,它与前面的属性有所不同,一般出现在如下的情形:在控件中点右键,弹出菜单中会有一个属性的编辑,如下图的“Customize…”,点击该菜单项,会

出现如下图的属性编辑窗体:

事实上,这个窗体就是控件编写者本身提供了的一个窗体,那么怎样才能将一个窗体和一个控件绑定起来?并且使得对窗体中值的修改影响到控件的属性值?(事实上,这种属性还是很多的,比如TImageList、TTreeView等)

下面还是通过一个实例来介绍:

TEditorForm: TForm; // 这是一个属性窗口类

TControl: TWinControl; // 这是控件类

假设这两个类已经写好了。

EditorForm: TEditorForm;

Control: TControl;

是两个类的实例。

TComponentEditor用于实现将用户在控件右键菜单上的点击动作映射到属性窗口,从而实现点击不同的菜单项打开不同的属性窗口。

它主要有三个方法:

function GetVerb(Index: Integer): string; override;

它表示菜单上第Index个菜单项的Caption值(如上图中的Customize…)

function GetVerbCount: Integer; override;

它表示一共有多少个菜单项

procedure ExecuteVerb(Index: Integer); override;

它表示点击第Index个菜单项时执行的操作

下面给出一个实例:

type

TControlEditor = class(TComponentEditor)

public

function GetVerb(Index: Integer): string; override;

function GetVerbCount: Integer; override;

procedure ExecuteVerb(Index: Integer); override;

end;

function TControlEditor.GetVerb(Index: Integer): string;

Begin

Result := '&Edit Items...';

End;

function TControlEditor.GetVerbCount: Integer;

Begin

Result := 1;

End;

procedure TControlEditor.ExecuteVerb(Index: Integer);

var

Dlg: TEditorForm;

Begin

Dlg:= TEditorForm.Create(Application);

Try

Dlg.ShowModal;

if Dlg.ModalResult = mrOK then

begin

if Dlg.Modified then

begin

CopyProperty(Dlg, Component); // 将修改过的属性赋值到控件中

Designer.Modified;

end;

end;

finally

Dlg.Free;

End;

End;

最后,要使得两控件和属性之间的映射关系被系统在设计时感知,必须在Register方法中增加RegisterComponentEditor方法的调用,如下例:

procedure Register;

begin

RegisterComponentEditor(TControl, TControlEditor);

end;

###############################################################################

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有