我有一个包含大量事件处理程序的设计和运行时组件。我现在称之为TNewComp。我在TForm上创建一个TNewComp实例,并在设计时通过属性编辑器用特定代码填充事件存根,并意识到我希望能够创建使用当前事件处理程序代码集的TNewcomp的新实例。
现在,我调用TNewComp的构造函数,然后“手动”为每个新实例的事件处理程序分配驻留在包含在设计时创建的TNewComp实例的表单上的相应事件存根代码。因此,如果我在一个名为TNewForm的表单上为一个名为FNewComp的变量分配了一个TNewComp实例,那么对于每个事件处理程序,我会这样做:
FNewComp.onSomething = TNewform.onSomething
(... repeat for each event handler belonging to TNewComp ...)
这很好,但是它很麻烦,更糟糕的是,如果我向TNewComp添加一个新的事件处理程序,我必须记得更新我的“newTComp()”函数来进行事件处理程序的分配。为我创建动态新实例的每个唯一组件类型冲洗并重复此过程。
是否可以使用属性检查或其他Delphi 6内省技术自动化此过程?
- roschler
答案 0 :(得分:4)
我使用了以下代码。在创建时要小心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;
答案 1 :(得分:2)
一种选择是将“正确设置的组件”保存到流中,然后将该strem加载到新的动态创建的组件中,就好像它是由Delphi IDE / runtime完成的。
另一个选择是使用RTIn,即TypInfo单元。你有函数GetPropList
,你可以查询可用的事件(TypeKind tkMethod
),然后你可以使用GetMethodProp
和SetMethodProp
将事件处理程序从一个组件复制到其他组件
答案 2 :(得分:1)
我将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参数)。如果有人能看到这个变种导致的缺陷或问题,请发表评论。