Delphi 是否可以获得组件';方法值(表示名称)?

Delphi 是否可以获得组件';方法值(表示名称)?,delphi,Delphi,我需要获取一个组件的名称(TButton),该组件在设计时被分配,并在对象检查器中显示(例如按钮1在按钮1处单击。在事件选项卡上单击事件) 我现在使用TypInfo单元通过PPropInfo获取方法信息,并将OnClick和TNotifyEvent字符串作为值,但没有将按钮1click作为字符串值 我怎样才能得到它 string := MethodName(GetMethodProp(Button1, 'OnClick').Code); 请注意,该方法需要“发布” 请注意,需要“发布”该方法。

我需要获取一个组件的名称(TButton),该组件在设计时被分配,并在对象检查器中显示(例如
按钮1在
按钮1处单击
。在事件选项卡上单击
事件)

我现在使用TypInfo单元通过
PPropInfo
获取方法信息,并将
OnClick
TNotifyEvent
字符串作为值,但没有将
按钮1click
作为字符串值

我怎样才能得到它

string := MethodName(GetMethodProp(Button1, 'OnClick').Code);
请注意,该方法需要“发布”


请注意,需要“发布”该方法。

如果属性和分配的方法都已发布
,则可以使用以下方法:

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;
TypInfo
单元(其中
GetMethodProp()
来自)仅支持
published
属性

您必须指定拥有方法地址的对象,因为
TObject.MethodName()
迭代对象的VMT。并且该方法必须是
已发布的
,因为
TObject.MethodName()
(其存在是为了方便DFM流式传输)迭代VMT的一部分,该部分仅填充
已发布的
方法的地址

如果您使用的是Delphi 2010或更高版本,则可以改用扩展RTTI,该RTTI没有发布的
限制:

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;

如果属性和指定的方法都已发布
,则可以使用:

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;
TypInfo
单元(其中
GetMethodProp()
来自)仅支持
published
属性

您必须指定拥有方法地址的对象,因为
TObject.MethodName()
迭代对象的VMT。并且该方法必须是
已发布的
,因为
TObject.MethodName()
(其存在是为了方便DFM流式传输)迭代VMT的一部分,该部分仅填充
已发布的
方法的地址

如果您使用的是Delphi 2010或更高版本,则可以改用扩展RTTI,该RTTI没有发布的
限制:

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;


这还假设该方法是由表单实现的+1
GetMethodProp()
返回一个
TMethod
TMethod.Data
字段指向传递给方法的
Self
参数的对象。在99%的情况下,您可以将
TMethod.Data
类型转换为
TObject
,然后使用该对象调用
TObject.MethodName()
,将
TMethod.code
作为地址,因为地址将属于该对象的类。这在所有情况下都应该有效,即使在运行时在代码中分配了事件。@RemyLebeau如果没有在那里分配方法或AV,它是否可以工作?顺便说一句-谢谢!明天上班时我会试试;)已经检查过了!一切正常!如果未分配任何内容,则不存在AV-仅存在“”(空字符串)。@notricky:它必须在源代码中
发布
,在运行时不能更改为
发布
。有关更多详细信息,请参阅。这还假设该方法由表单实现+1
GetMethodProp()
返回一个
TMethod
TMethod.Data
字段指向传递给方法的
Self
参数的对象。在99%的情况下,您可以将
TMethod.Data
类型转换为
TObject
,然后使用该对象调用
TObject.MethodName()
,将
TMethod.code
作为地址,因为地址将属于该对象的类。这在所有情况下都应该有效,即使在运行时在代码中分配了事件。@RemyLebeau如果没有在那里分配方法或AV,它是否可以工作?顺便说一句-谢谢!明天上班时我会试试;)已经检查过了!一切正常!如果未分配任何内容,则不存在AV-仅存在“”(空字符串)。@notricky:它必须在源代码中
发布
,在运行时不能更改为
发布
。有关更多详细信息,请参阅。TObject的演员阵容过于武断。
Data
指针可以引用类而不是实例。或者确实是一个记录或一个TP对象。知道它是多么伟大@大卫·费弗南处理这个问题的方法是什么?@notricky这真的是你的问题吗?您不会从TP对象中获得任何RTTI,但谁会关心它们呢?至于记录或类类型,不确定如何识别它们。知道你为什么问这个问题会很有趣。@DavidHeffernan,这很公平。我正在编写一个
SmallClass
,在这里我传递自身和外部组件
Component
有自己的方法,我需要找到这些方法并用这些方法重新分配,这些方法位于
self
的实例中。当
Component
self
都有相同的方法名时,应该会发生这种情况:
Component.OnClick-'ComponentClick'
self.ComponentClick
。因此,我不仅需要从
Component
中发布的属性中获取信息,还需要从
self
中获取信息。我真的不明白为什么需要使用内省,但在任何情况下,除了方法指针的原始数据之外,我看不到任何需要了解的信息。我认为这两个答案,在回答你的问题时,都比你需要的复杂。换言之,我认为你问错了问题。TObject的演员阵容是自以为是的。
Data
指针可以引用类而不是实例。或者确实是一个记录或一个TP对象。知道它是多么伟大@大卫·费弗南处理这个问题的方法是什么?@notricky这真的是你的问题吗?您不会从TP对象中获得任何RTTI,但谁会关心它们呢?至于记录或类类型,不确定如何识别它们。知道你为什么问这个问题会很有趣。@DavidHeffernan,这很公平。我正在编写一个
SmallClass
,在这里我传递自身和外部组件<代码>组件
有自己的方法,我需要找到并重新分配这些方法