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



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

现在,我调用TNewComp的构造函数,然后"手动"为每个新实例的事件处理程序分配相应的事件存根代码,该代码驻留在包含设计时创建的TNewComp实例的表单中。因此,如果我有一个tnewp的实例赋值给一个名为fnewp的变量在一个名为TNewForm的表单上,对于每个事件处理程序,我将做:

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

这工作得很好,但它是麻烦的,更糟的是,如果我添加一个新的事件处理程序到tcomp,我必须记得更新我的"newTComp()"函数,使事件处理程序分配。对于我动态创建新实例的每个唯一组件类型,重复这个过程。

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

——roschler

我使用了以下代码。创建时要小心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;

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

另一个选择是使用RTTI,即TypInfo单元。在那里你有功能GetPropList女巫将使您能够查询可用的事件(类型tkMethod),然后你可以使用GetMethodPropSetMethodProp复制事件处理程序从一个组件到另一个。

我将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形参)。如果有人能看到这个变体导致的缺陷或问题,请评论。

相关内容

  • 没有找到相关文章

最新更新