有没有办法在 Delphi 6 中自动分配动态创建的组件的事件处理程序?

发布于 2024-11-18 15:55:53 字数 625 浏览 4 评论 0原文

我有一个设计和运行时组件,其中包含大量事件处理程序。我现在将其称为 TNewComp。我在 TForm 上创建一个 TNewComp 实例,并在设计时通过属性编辑器用特定代码填充事件存根,并意识到我希望能够创建使用当前事件处理程序代码集的 TNewcomp 的新实例。

现在要执行此操作,我调用 TNewComp 的构造函数,然后“手动”为每个新实例的事件处理程序分配驻留在包含设计时创建的 TNewComp 实例的表单上的相应事件存根代码。因此,如果我将 TNewComp 的实例分配给名为 TNewForm 的表单上名为 FNewComp 的变量,则对于每个事件处理程序,我会这样做:

FNewComp.onSomething = TNewform.onSomething
(... repeat for each event handler belonging to TNewComp ...)

这工作正常,但很麻烦,而且更糟,如果我向 TNewComp 添加新的事件处理程序,我会这样做:必须记住更新我的“newTComp()”函数以进行事件处理程序分配。对于我动态创建新实例的每个独特组件类型,冲洗并重复此过程。

有没有办法自动化这个过程,也许使用属性检查或其他一些 Delphi 6 内省技术?

——罗施勒

I have a design and run-time component that contains a large number of event handlers. I'll call it TNewComp for now. I create an instance of TNewComp on a TForm and fill in the event stubs with specific code via the property editor at design time, and realize I would like to be able to create new instances of TNewcomp that use the current set of event handler code.

To do this now, I call TNewComp's constructor and then "manually" assign each of the new instance's event handlers the corresponding event stub code resident on the form that contains the TNewComp instance created at design time. So if I have an instance of TNewComp assigned to a variable named FNewComp on a form called TNewForm, for each event handler I would do:

FNewComp.onSomething = TNewform.onSomething
(... repeat for each event handler belonging to TNewComp ...)

This works fine, but it is cumbersome and worse, if I add a new event handler to TNewComp, I have to remember to update my "newTComp()" function to make the event handler assignment. Rinse and repeat this process for every unique component type that I create new instances of dynamically.

Is there way to automate this process, perhaps using property inspection or some other Delphi 6 introspection technique?

-- roschler

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

亢潮 2024-11-25 15:55:53

我使用了以下代码。创建时要小心 Dest 所有者,最安全的方法是传递 Nil 并稍后自行释放组件。

implementation uses typinfo;

procedure CopyComponent(Source, Dest: TComponent);
var
  Stream: TMemoryStream;
  TypeData : PTypeData;
  PropList: PPropList;
  i, APropCount: integer;
begin
  Stream:=TMemoryStream.Create;
  try
    Stream.WriteComponent(Source);
    Stream.Position:=0;
    Stream.ReadComponent(Dest);
  finally
    Stream.Free;
  end;

  TypeData := GetTypeData(Source.ClassInfo);
  if (TypeData <> nil) then
  begin
    GetMem(PropList, SizeOf(PPropInfo)*TypeData^.PropCount);
    try
      APropCount:=GetPropList(Source.ClassInfo, [tkMethod], PropList);
      for i:=0 to APropCount-1 do
        SetMethodProp(Dest, PropList[i], GetMethodProp(Source, PropList[i]))
    finally
      FreeMem(PropList);
    end;
  end;
end;

I used the following code. Be careful with the Dest owner when creating, the safest way is to pass Nil and free the component by yourself later.

implementation uses typinfo;

procedure CopyComponent(Source, Dest: TComponent);
var
  Stream: TMemoryStream;
  TypeData : PTypeData;
  PropList: PPropList;
  i, APropCount: integer;
begin
  Stream:=TMemoryStream.Create;
  try
    Stream.WriteComponent(Source);
    Stream.Position:=0;
    Stream.ReadComponent(Dest);
  finally
    Stream.Free;
  end;

  TypeData := GetTypeData(Source.ClassInfo);
  if (TypeData <> nil) then
  begin
    GetMem(PropList, SizeOf(PPropInfo)*TypeData^.PropCount);
    try
      APropCount:=GetPropList(Source.ClassInfo, [tkMethod], PropList);
      for i:=0 to APropCount-1 do
        SetMethodProp(Dest, PropList[i], GetMethodProp(Source, PropList[i]))
    finally
      FreeMem(PropList);
    end;
  end;
end;
老旧海报 2024-11-25 15:55:53

一种选择是将“正确设置的组件”保存到流中,然后将该流加载到新的动态创建的组件中,就好像它是由 Delphi IDE/运行时完成的一样。

另一种选择是使用 RTTI(TypInfo 单元)。那里有函数 GetPropList ,它将使您能够查询可用事件(TypeKind tkMethod),然后您可以使用 GetMethodPropSetMethodProp 将事件处理程序从一个组件复制到另一个组件。

One option would be to save "the properly set up component" into stream and then load that strem into new, dynamically created component as if it is done by Delphi IDE/runtime.

Another option is to use RTTI, the TypInfo unit. There you have function GetPropList witch will enable you to query for available events (TypeKind tkMethod) and then you can use GetMethodProp and SetMethodProp to copy eventhandlers from one component to other.

悲念泪 2024-11-25 15:55:53

我将 Maksee 的解决方案调整为以下内容:

function CopyComponent(Source: TComponent; Owner: TComponent = nil): TComponent;
var
    Stream: TMemoryStream;
    TypeData : PTypeData;
    PropList: PPropList;
    i, APropCount: integer;
begin
    if not Assigned(Source) then
        raise Exception.Create('(CopyComponent) The Source component is not assigned.');

    Result := TComponent.Create(Owner);

    Stream := TMemoryStream.Create;

    try
        Stream.WriteComponent(Source);
        Stream.Position := 0;
        Stream.ReadComponent(Result);
    finally
        Stream.Free;
    end; // try()

    // Get the type data for the Source component.
    TypeData := GetTypeData(Source.ClassInfo);

    if (TypeData <> nil) then
    begin
        // Get the property information for the source component.
        GetMem(PropList, SizeOf(PPropInfo) * TypeData^.PropCount);

        try
            // Get the properties count.
            APropCount := GetPropList(Source.ClassInfo, [tkMethod], PropList);

            // Assign the source property methods to the destination.
            for i := 0 to APropCount - 1 do
                SetMethodProp(Result, PropList[i], GetMethodProp(Source, PropList[i]))

        finally
            // Free the property information object.
            FreeMem(PropList);
        end; // try()
    end; // if (TypeData <> nil) then
end;

以便函数返回一个新组件,而不是传入现有组件引用(Maksee 版本中的 Dest 参数)。如果有人发现此变体会导致缺陷或问题,请发表评论。

I tweaked Maksee's solution to the following:

function CopyComponent(Source: TComponent; Owner: TComponent = nil): TComponent;
var
    Stream: TMemoryStream;
    TypeData : PTypeData;
    PropList: PPropList;
    i, APropCount: integer;
begin
    if not Assigned(Source) then
        raise Exception.Create('(CopyComponent) The Source component is not assigned.');

    Result := TComponent.Create(Owner);

    Stream := TMemoryStream.Create;

    try
        Stream.WriteComponent(Source);
        Stream.Position := 0;
        Stream.ReadComponent(Result);
    finally
        Stream.Free;
    end; // try()

    // Get the type data for the Source component.
    TypeData := GetTypeData(Source.ClassInfo);

    if (TypeData <> nil) then
    begin
        // Get the property information for the source component.
        GetMem(PropList, SizeOf(PPropInfo) * TypeData^.PropCount);

        try
            // Get the properties count.
            APropCount := GetPropList(Source.ClassInfo, [tkMethod], PropList);

            // Assign the source property methods to the destination.
            for i := 0 to APropCount - 1 do
                SetMethodProp(Result, PropList[i], GetMethodProp(Source, PropList[i]))

        finally
            // Free the property information object.
            FreeMem(PropList);
        end; // try()
    end; // if (TypeData <> nil) then
end;

So that a new component is returned by the function rather than passing in an existing component reference (the Dest parameter in Maksee's version). If anyone can see a flaw or problem that will result from this variant please comment.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文