Reputation: 179
I need to get a name of a component (TButton), that is being assigned in design-time and is seen in Object Inspector (such as Button1Click
at Button1.OnClick
event on events tab).
I use now TypInfo unit to get method's information via PPropInfo
and I get OnClick
and TNotifyEvent
strings as values, but I didn't get the Button1Click
as string value.
How can I get it?
Upvotes: 1
Views: 1954
Reputation: 595827
If the property and assigned method are both published
, you can use this:
uses
TypInfo;
function GetEventHandlerName(Obj: TObject; const EventName: String): String;
var
m: TMethod;
begin
m := GetMethodProp(Obj, EventName);
if (m.Data <> nil) and (m.Code <> nil) then
Result := TObject(m.Data).MethodName(m.Code)
else
Result := '';
end;
s := GetEventHandlerName(Button1, 'OnClick');
The TypInfo
unit (where GetMethodProp()
comes from) only supports published
properties.
You have to specify the object that owns the method address because TObject.MethodName()
iterates the object's VMT. And the method must be published
because TObject.MethodName()
(which exists to facilitate DFM streaming) iterates a portion of the VMT that is filled only with the addresses of published
methods.
If you are using Delphi 2010 or later, you can use Extended RTTI instead, which does not have the published
limitations:
uses
Rtti;
function GetEventHandlerName(Obj: TObject; const EventName: String): String;
type
PMethod = ^TMethod;
var
ctx: TRttiContext;
v: TValue;
_type: TRttiType;
m: TMethod;
method: TRttiMethod;
s: string;
begin
Result := '';
ctx := TRttiContext.Create;
v := ctx.GetType(Obj.ClassType).GetProperty(EventName).GetValue(Obj);
if (v.Kind = tkMethod) and (not v.IsEmpty) then
begin
// v.AsType<TMethod>() raises an EInvalidCast exception
// and v.AsType<TNotifyEvent>() is not generic enough
// to handle any kind of event. Basically, the Generic
// parameter of AsType<T> must match the actual type
// that the event is declared as. You can use
// TValue.GetReferenceToRawData() to get a pointer to
// the underlying TMethod data...
m := PMethod(v.GetReferenceToRawData())^;
_type := ctx.GetType(TObject(m.Data).ClassType);
for method in _type.GetMethods do
begin
if method.CodeAddress = m.Code then
begin
Result := method.Name;
Exit;
end;
end;
end;
s := GetEventHandlerName(Button1, 'OnClick');
Upvotes: 4
Reputation: 54792
string := MethodName(GetMethodProp(Button1, 'OnClick').Code);
Note that the method needs to be 'published'.
Upvotes: 6