分享
 
 
 

DELPHI中使用RTTI

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

运行期类型信息(RTTI)是一种语言特征,能使应用程序在运行时得到关于对象的信息。RTTI是Delphi的组件能够融合到IDE中的关键。它在IDE中不仅仅是一个纯学术的过程。

由于对象都是从TObject继承下来的,因此,对象都包含一个指向它们的RTTI的指针以及几个内建的方法。下面的表列出了TObject的一些方法,用这些方法能获得某个对象实例的信息。

函数

返回类型

返回值

ClassName( )

string

对象的类名

ClassType()

boolean

对象的类型

InheritsFrom

boolean

判断对象是否继承于一个指定的类

ClassParent()

TClass

对象的祖先类型

Instancesize()

word

对象实例的长度(字节数)

ClassInfo()

Pointer

指向RTTI的指针

第一部分:关于as 和 is

Object Pascal提供了两个运算符as和is,用它们通过RTTI能对对象进行比较和强制类型转换。

关键字as是类型转换的一种新的形式。它能把一个基层的对象强制类型转换成它的派生类,如果转换不合法就产生一个异常。假定有一个过程,想让它能够传递任何类型的对象,它应该这样定义:

Procedure Foo(AnObject :Tobject);

在这个过程如果要对AnObject进行操作,要把它转换为一个派生对象。假定把AnObject看成是一个TEdit派生类型,并想要改变它所包含的文本,用下列代码: (AnObject as Tedit).text := 'wudi_1982';

能用比较运算符来判断两个对象是否是相兼容的类型,用is运算符把一个未知的对象和一个已知类型或实例进行比较,确定这个未知对象的属性和行为。例如,在对(AnObject 进行强制类型转换前,确定(AnObject 和TEdit是否指针兼容:

if (AnObject is Tedit) then

Tedit(AnObjject).text := 'wudi_1982';

注意在这个例子中不要再使用as进行强制类型转换,这是因为它要大量使用RTTI,另外还因为,在第一行已经判断Foo就是TEdit,可以通过在第2行进行指针转换来优化。

这两个操作符最典型的应用我想应该是在程序需要的部分清空窗体上所有edit的text属性

procedure TForm1.ClearEdit(Acontrl: TWinControl);

var

i : integer;

begin

for i := 0 to Acontrl.ControlCount-1 do

begin

if Acontrl.Controls[i] is TEdit then

((Acontrl.Controls[i]) as TEdit).Text := '';

if Acontrl.Controls[i] is TCustomControl then

ClearEdit( (Acontrl.Controls[i] as TCustomControl))

end;

end;

第二部分:RTTI

上文中已经多次提到了RTTI,但好像并没有看到RTTI出现。那么RTTI是如何表现自己的呢?你将发现, RTTI至少在两个地方对你有用。第一个地方是DELPHI的IDE,这在前面已提到过。通过RTTI,IDE就会知道你正在使用的对象和组件的任何事情。实际上,不只是RTTI,但为了这个讨论,我们只谈RTTI方面。其实上面的as,is操作都间接的使用了RTTI。

还是用个例子来演示吧。在观看此例子之时,建议你看看typinfo.pas中的内容(DELPHI安装目录下\source\rtl\common\TypInfo.pas);

下面的例子主要分为两部分,界面上半部分,主要演示通过rtti来显示用户选择类型的信息。(有3个TListBox)。

下面的部分主要通过RTTI来完成通过配置信息对控件进行属性的赋值操作,这里将演示文本类型和事件类型的赋值。

窗体文件如下:代码如下:

object Form1: TForm1

Left = 150

Top = 161

Width = 639

Height = 372

Caption = 'Form1'

Color = clBtnFace

Font.Charset = DEFAULT_CHARSET

Font.Color = clWindowText

Font.Height = -11

Font.Name = 'Tahoma'

Font.Style = []

OldCreateOrder = False

OnCreate = FormCreate

PixelsPerInch = 96

TextHeight = 13

object Panel1: TPanel

Left = 0

Top = 0

Width = 631

Height = 185

Align = alTop

TabOrder = 0

object GroupBox1: TGroupBox

Left = 1

Top = 1

Width = 185

Height = 183

Align = alLeft

Caption = '在这里选择要查看类型的信息'

TabOrder = 0

object ListBox1: TListBox

Left = 2

Top = 15

Width = 181

Height = 166

Align = alClient

ItemHeight = 13

TabOrder = 0

OnClick = ListBox1Click

end

end

object GroupBox2: TGroupBox

Left = 368

Top = 1

Width = 262

Height = 183

Align = alRight

Caption = '属性信息'

TabOrder = 1

object ListBox3: TListBox

Left = 2

Top = 15

Width = 258

Height = 166

Align = alClient

ItemHeight = 13

TabOrder = 0

end

end

object GroupBox3: TGroupBox

Left = 186

Top = 1

Width = 182

Height = 183

Align = alClient

Caption = '基本信息'

TabOrder = 2

object ListBox2: TListBox

Left = 2

Top = 15

Width = 178

Height = 166

Align = alClient

ItemHeight = 13

TabOrder = 0

end

end

end

object TPanel

Left = 0

Top = 185

Width = 631

Height = 157

Align = alClient

TabOrder = 1

object Panel2: TPanel

Left = 1

Top = 1

Width = 230

Height = 155

Align = alLeft

TabOrder = 0

object Label2: TLabel

Left = 10

Top = 8

Width = 84

Height = 13

Caption = '要修改的控件名'

end

object Label3: TLabel

Left = 8

Top = 32

Width = 72

Height = 13

Caption = '修改的属性名'

end

object Label4: TLabel

Left = 8

Top = 64

Width = 72

Height = 13

Caption = '将属性修改为'

end

object edComName: TEdit

Left = 104

Top = 5

Width = 78

Height = 21

TabOrder = 0

Text = 'label1'

end

object edPproName: TEdit

Left = 104

Top = 32

Width = 81

Height = 21

TabOrder = 1

Text = 'caption'

end

object edValue: TEdit

Left = 104

Top = 56

Width = 81

Height = 21

TabOrder = 2

Text = '12345'

end

object btnInit: TButton

Left = 8

Top = 104

Width = 75

Height = 25

Caption = '初始化'

TabOrder = 3

OnClick = btnInitClick

end

object btnModify: TButton

Left = 104

Top = 104

Width = 75

Height = 25

Caption = '修改'

TabOrder = 4

OnClick = btnModifyClick

end

end

object Panel3: TPanel

Left = 231

Top = 1

Width = 399

Height = 155

Align = alClient

TabOrder = 1

object GroupBox4: TGroupBox

Left = 1

Top = 1

Width = 397

Height = 153

Align = alClient

Caption = '被修改的控件'

TabOrder = 0

object Label1: TLabel

Left = 16

Top = 32

Width = 28

Height = 13

Caption = 'label1'

end

object BitBtn1: TBitBtn

Left = 8

Top = 64

Width = 75

Height = 25

Caption = 'BitBtn1'

TabOrder = 0

end

end

end

end

end

...{

作者:wudi_1982

联系方式:wudi_1982@hotmail.com

转载请注明出处

}

unit main;

interface

uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,

Forms,

Dialogs,typinfo, StdCtrls, ExtCtrls, Buttons;

type

InsertCom = record

Name : string; //要修改属性的组件名

PproName : string;//要修改控件的属性名

MethodName :string;//要修改or添加给控件的事件名

text : string; //属性值,这里修改的是string类型的数值

end;

TForm1 = class(TForm)

Panel1: TPanel;

GroupBox1: TGroupBox;

ListBox1: TListBox;

GroupBox2: TGroupBox;

GroupBox3: TGroupBox;

ListBox2: TListBox;

ListBox3: TListBox;

Panel2: TPanel;

edComName: TEdit;

Label2: TLabel;

Label3: TLabel;

edPproName: TEdit;

Label4: TLabel;

edValue: TEdit;

Panel3: TPanel;

btnInit: TButton;

btnModify: TButton;

GroupBox4: TGroupBox;

Label1: TLabel;

BitBtn1: TBitBtn;

procedure FormCreate(Sender: TObject);

procedure ListBox1Click(Sender: TObject);

procedure btnInitClick(Sender: TObject);

procedure btnModifyClick(Sender: TObject);

private

TestCom : InsertCom;

procedure MyClick(Sender : TObject); //给控件添加onclick事件

public

...{ Public declarations }

end;

var

Form1: TForm1;

implementation

...{$R *.dfm}

function CreateClass(const AClassName : string):TObject;//根据名字生成

var

tm : TObject;

t : TFormClass;

begin

t := TFormClass(FindClass(AClassName));

tm := t.Create(nil);

Result := tm;

end;

procedure GetBaseClassInfo(AClass : TObject;AStrings : TStrings); //获

得类型的基本信息

var

classTypeInfo : PTypeInfo;

ClassDataInfo : PTypeData;

begin

classTypeInfo := AClass.ClassInfo;

ClassDataInfo := GetTypeData(classTypeInfo);

with AStrings do

begin

Add(Format('name is :%s',[classTypeInfo.Name]));

Add(format('type kind is :%s',[GetEnumName(TypeInfo

(TTypeKind),integer(classTypeInfo.Kind))]));

Add(Format('in : %s',[ClassDataInfo.UnitName]));

end;

end;

procedure GetBaseClassPro(AClass : TObject;Astrings : TStrings); //获

得属性信息

var

NumPro : integer; //用来记录事件属性的个数

Pplst : PPropList; //存放属性列表

Classtypeinfo : PTypeInfo;

classDataInfo: PTypeData;

i : integer;

begin

Classtypeinfo := AClass.ClassInfo;

classDataInfo := GetTypeData(Classtypeinfo);

if classDataInfo.PropCount <> 0 then

begin

//分配空间

GetMem(Pplst,sizeof(PpropInfo)*classDataInfo.PropCount);

try

//获得属性信息到pplst

GetPropInfos(AClass.ClassInfo,Pplst);

for I := 0 to classDataInfo.PropCount - 1 do

begin

if Pplst[i]^.PropType^.Kind <> tkMethod then

//这里过滤掉了事件属性

Astrings.Add(Format('%s:%s',[Pplst[i]^.Name,Pplst[i]

^.PropType^.Name]));

end;

//获得事件属性

NumPro := GetPropList(AClass.ClassInfo,[tkMethod],Pplst);

if NumPro <> 0 then

begin

//给列表添加一些标志

Astrings.Add('');

Astrings.Add('-----------EVENT-----------');

Astrings.Add('');

for i := 0 to NumPro - 1 do //获得事件属性的列表

Astrings.Add(Format('%s:%s',[Pplst[i]^.Name,Pplst[i]

^.PropType^.Name]));

end;

finally

FreeMem(Pplst,sizeof(PpropInfo)*classDataInfo.PropCount);

end;

end;

end;

procedure TForm1.btnInitClick(Sender: TObject);

begin

//修改label1的caption属性为12345

TestCom.Name := edComName.Text;

TestCom.PproName := edPproName.Text;

TestCom.text := edValue.Text;

TestCom.MethodName := 'OnClick';

btnModify.Enabled := true;

end;

procedure TForm1.btnModifyClick(Sender: TObject);

var

pp : PPropInfo;

obj : TComponent;

a : TMethod;

tm : TNotifyEvent;

begin

obj := FindComponent(TestCom.Name);//通过名字查找此控件

if not Assigned(obj) then exit; //如果没有则退出

//通过getPropInfo获得指定控件的属性信息,注意,这里只能获得那些公开

了的属性

pp := GetPropInfo(obj.ClassInfo,TestCom.PproName);

if Assigned(pp) then

begin

//根据kind判断类型是否为string类型

case pp^.PropType^.Kind of

//这里使用setStrProp来为string类型的属性赋值,对起来类型的赋值

,请参考TypInfo.pas

tkString,tkLString,tkWString : SetStrProp

(obj,TestCom.PproName,TestCom.text);

end;

//给要修改的控件添加onClick事件,

pp := GetPropInfo(obj.ClassInfo,TestCom.MethodName);

if Assigned(pp) then

begin

if pp^.PropType^.Kind = tkMethod then

begin

tm := MyClick;

//Tmethod的code为函数地址,你也可以通过MethodAddress方法获得

a.Code := @tm;

a.Data := Self;

//对时间赋值

SetMethodProp(obj,TestCom.MethodName,a);

end;

end;

end;

end;

procedure TForm1.FormCreate(Sender: TObject);

begin

btnModify.Enabled := false;

//给listbox1添加一些类型的类名

with ListBox1.Items do

begin

Add('TApplication');

Add('TEdit');

Add('TButton');

Add('Tmemo');

Add('TForm');

end;

end;

procedure TForm1.ListBox1Click(Sender: TObject);

var

t : TObject;

begin

//当在类型列表中选择一个类型并用鼠标单击后,分别得到它的属性信息和

基本信息

ListBox2.Clear;

ListBox3.Clear;

t := CreateClass(ListBox1.Items[ListBox1.ItemIndex]);

try

GetBaseClassInfo(t,ListBox2.Items);

GetBaseClassPro(t,ListBox3.Items);

finally

t.Free;

end;

end;

procedure TForm1.MyClick(Sender: TObject);

begin

//给指定控件添加的一个方法

ShowMessage('wudi_1982');

end;

initialization

//初始化的时候注册

RegisterClasses([TApplication,TButton,TEdit,TMemo,TForm]);

end.

注:示例程序在winxp+D7以及turbo delphi+winxp下测试通过。Borland文档中不包含将来也许会有版本变化的功能。当使用如RTTI等无文档说明的功能时,就不能保证你的程序可以完全移植到Delphi的未来版本。转载请注明出处!

程序效果图如下:

编译、运行程序,你可以通过点击左上角列表框中的类型,获得他们的信息。而在窗体的下部,主要演示了通过读取配置信息来对控件的属性赋值(例程中的配置信息是通过edit输入的,可以在实际运用中改成从配置文件读取)。当使用下半部分功能时,在默认情况下,点击初始化按钮,然后点击修改,你会发现label1的caption变成了12345,并在在鼠标点击的时候会弹出一个对话框,你可以尝试把第一个edit的内容改成bitbtn1试试。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
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- 王朝網路 版權所有