有关RTTI,请问如何从一个控件中通过一个事件名称得到该事件的类型信息PTypeInfo(有一定难度)? ( 积分: 300 )

  • 主题发起人 主题发起人 dejoy
  • 开始时间 开始时间
D

dejoy

Unregistered / Unconfirmed
GUEST, unregistred user!
有关RTTI,请问如何从一个控件中通过一个事件名称得到该事件的类型信息PTypeInfo(有一定难度)?在此虚心请教各位达人。
比如给定TButton,及名称'OnClick',如何得到OnClick对应的事件的PTypeInfo?
函数定义如下:
function GetEventTypeInfo(ComponentClass:TPersistentClass; EventName: string):PTypeInfo;
begin
//??? 这里如何实现?
end;
调用:GetEventTypeInfo(TButton,'OnClick');
因为只知道一个类名和一个事件名,而不知道具体的事件类型,所以不能直接使用TypeInfo(TNotifyEvent)这样的方式直接取得事件的类型信息,而要通过类和事件名来取得,事件是published的。
 
通过分析Typinfo.pas,初步实现了如下代码,希望有达人能进一步。
function GetEventTypeInfo(ComponentClass:TPersistentClass; EventName: string):PTypeInfo;
var
p:PPropInfo;
begin
p:= GetPropInfo(ComponentClass,EventName,tkMethods);
if p <> nil then
result := p^.PropType^;
end;
 
取得PTypeInfo有什么用呢
PTypeInfo = ^TTypeInfo;
TTypeInfo = record
Kind: TTypeKind; //tkMethods,这个已知了
Name: ShortString; //'OnClick' 这个也已知了
{TypeData: TTypeData}
end;

不如果直接写了
function GetEventTypeInfo(ComponentClass: TPersistentClass; EventName: string): PTypeInfo;
begin
Result^.Kind := tkMethod;
Result^.Name := EventName;
end;
 
取得PTypeInfo有什么用呢=>>
当然有用,在delphi7中的DesignEditors.pas中有一个函数:
procedure RegisterPropertyEditor(PropertyType: PTypeInfo; ComponentClass: TClass;
const PropertyName: string; EditorClass: TPropertyEditorClass);
其中第一个参数PropertyType需要传入的就是一个PTypeInfo类型的。简单的解释下用途,
我要用GetEventTypeInfo动态的取得一个类(不是类的实例)的published的事件的PTypeInfo,如果该类存在这个事件,就传到RegisterPropertyEditor动态注册一个该事件的PropertyEditor,这样解释明白了吗?

不如果直接写了
function GetEventTypeInfo(ComponentClass: TPersistentClass; EventName: string): PTypeInfo;
begin
Result^.Kind := tkMethod;
Result^.Name := EventName;
end;

》》呵呵 ,大哥,这不行啊,如果按你那样,比如我这样执行GetEventTypeInfo(TButton,'OnClickXXX'),返回的是非nil的值,因为TButton类根本没有OnClickXXX事件,正确的返回应该是一个nil值。
 
ANiDelphi =》我查看了一下VCL代码,PTypeInfo 的定义如下
PTypeInfo = ^TTypeInfo;
TTypeInfo = record
Kind: TTypeKind;
Name: ShortString;
{TypeData: TTypeData}
end;

PTypeInfo = ^TTypeInfo;
TTypeInfo = record
Kind: TTypeKind; //tkMethods,这个已知了
Name: ShortString; //'OnClick' 这个也已知了
{TypeData: TTypeData} //哈这个未知了吧?!
end;

不如果直接写了
 
PTypeInfo = ^TTypeInfo;
TTypeInfo = record
Kind: TTypeKind;
Name: ShortString;
{TypeData: TTypeData}
end;
不好意思,搞错了,光看了字面没测试
试了一下,发现如果是OnClick返回的TypeInfo.Name是TNotifyEvent,这个不是已知的
不过TypeData这个已经用{}注释了,说明在D7中已经不存在这个字段了,也就没所谓已知不已知了

你这个方法已经很不错了,不过会出现 Return value ... might be undefined的提示,稍微改动了一下
function GetEventTypeInfo(ComponentClass: TPersistentClass; EventName: string): PTypeInfo;
var
P: PPropInfo;
begin
P := GetPropInfo(ComponentClass, EventName, tkMethods);
if P <> nil then
Result := P.PropType^
else
Result := nil;
end;
 
关于TTypeInfo 的定义,是有些奇怪。TypeData看上去好像是被注释了,可实际上是真实存在的,似乎broland不想把它展示给开发者。
TTypeInfo = record
Kind: TTypeKind;
Name: ShortString;
{TypeData: TTypeData}
end;
还有,一个function返回的不是自动为Nil吗?
 
3年前的代码,今天上了一次.好久没有来.
procedure Tform1.GetClassPropertiesGrid(AClass: TObject;var AStrings: TStringGrid);
var
PropList: PPropList;
ClassTypeInfo: PTypeInfo;
ClassTypeData: PTypeData;
i,tmpint: integer;
tmpstr:string;
tmpobj:Tobject;
begin
ClassTypeInfo := AClass.ClassInfo;
ClassTypeData := GetTypeData(ClassTypeInfo);
if ClassTypeData.PropCount <> 0 then
begin
GetMem(PropList, SizeOf(PPropInfo) * ClassTypeData.PropCount);
try
GetPropInfos(AClass.ClassInfo, PropList);
AStrings.RowCount:=ClassTypeData.PropCount;
tmpint:=0;
for i := 0 to ClassTypeData.PropCount - 1 do
begin
tmpstr:='';
case PropList^.PropType^.Kind of
tkMethod:continue;
tkInteger,tkInt64,tkEnumeration:tmpstr:=GetEnumProp(AClass,PropList^.Name);
tkFloat:tmpstr:=floattostr(GetFloatProp(AClass,PropList^.Name));
tkString,tkLString,tkWString:tmpstr:=GetStrProp(AClass,PropList^.Name);
tkClass:begin
tmpobj:=GetObjectProp(AClass,PropList^.Name);
if (tmpobj<>nil) then
begin
if (tmpobj is Tcomponent) then
tmpstr:=Tcomponent(tmpobj).Name
else
tmpstr:='('+Tcomponent(tmpobj).ClassName+')';
end;
end;
end;
AStrings.Cells[0,i]:=PropList^.Name;
if tmpstr<>'' then
AStrings.Cells[1,i]:=tmpstr;
inc(tmpint);
end;
AStrings.RowCount:=tmpint;
finally
FreeMem(PropList, SizeOf(PPropInfo) * ClassTypeData.PropCount);
end;
end;
end;
procedure GetClassProperties(AClass: TObject; AStrings: TStrings);
var
PropList: PPropList;
ClassTypeInfo: PTypeInfo;
enumdata,ClassTypeData: PTypeData;
i,j,NumProps: integer;
tmpstr:string;
tmpobj:Tobject;
begin
ClassTypeInfo := AClass.ClassInfo;
ClassTypeData := GetTypeData(ClassTypeInfo);
if ClassTypeData.PropCount <> 0 then
begin
GetMem(PropList, SizeOf(PPropInfo) * ClassTypeData.PropCount);
try
GetPropInfos(AClass.ClassInfo, PropList);
for i := 0 to ClassTypeData.PropCount - 1 do
begin
tmpstr:='';
case PropList^.PropType^.Kind of
tkMethod:continue;
tkInteger,tkInt64:tmpstr:=inttostr(GetOrdProp(AClass,PropList^.Name));
tkEnumeration:begin
tmpstr:=GetEnumProp(AClass,PropList^.Name)+' {';
enumdata:=GetTypeData(PropList^.PropType^);
//下面两行可以进行非常大的优化
for j:=enumdata.MinValue to enumdata.MaxValue do
tmpstr:=tmpstr+GetEnumName(PropList^.PropType^,j)+',';
tmpstr[length(tmpstr)]:='}'
end;
tkFloat:tmpstr:=floattostr(GetFloatProp(AClass,PropList^.Name));
tkClass:begin
tmpobj:=GetObjectProp(AClass,PropList^.Name);
if (tmpobj<>nil) and (tmpobj is Tcomponent) then
tmpstr:=Tcomponent(tmpobj).Name;
end;
tkString,tkLString,tkWString:tmpstr:=#39+GetStrProp(AClass,PropList^.Name)+#39;
end;{case}
if tmpstr<>'' then
tmpstr:='='+tmpstr;
AStrings.Add(Format('%s: %s%s', [PropList^.Name, PropList^.PropType^.Name,tmpstr]));
end;
NumProps := GetPropList(AClass.ClassInfo, [tkMethod], PropList);
if NumProps <> 0 then
AStrings.Add('=========EVENTS================');
for i := 0 to NumProps - 1 do
begin
tmpstr:='';
if GetMethodProp(Aclass,PropList^.Name).data<>nil then
tmpstr:=' (have events)';
AStrings.Add(Format('%s: %s%s', [PropList^.Name, PropList^.PropType^.Name,tmpstr]));
end;
finally
FreeMem(PropList, SizeOf(PPropInfo) * ClassTypeData.PropCount);
end;
end;
end;
 
function GetTypeData(TypeInfo: PTypeInfo): PTypeData;
TypeData应该是用这个函数来取得的吧

没有说函数会自动返回nil的吧
function GetObject: TObject;
begin
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
if GetObject = nil then Caption := 'True';
end;
试了一下,如果不写返回值,那么并不返回nil
而把TObject改成Integer,也不是返回0
但改成string的话,却是返回的是空字符串
 
后退
顶部