是否有可能在运行时使用子类化组件替换和释放TEdit?如果是这样,应该如何做?我尝试在表单构造函数和AfterConstruction方法中将父级设置为nil并调用free(),但在两种情况下都出现了运行时错误。
更具体地说,我遇到了访问冲突错误(EAccessViolation)。当释放帧构造中的组件时,似乎会影响表单控件的管理,弗朗索瓦是正确的。
您需要调用TEdit的父控件的RemoveControl方法来删除该控件。使用InsertControl方法添加新控件。
var Edit2: TEdit;
begin
Edit2 := TEdit.Create(self);
Edit2.Left := Edit1.Left;
Edit2.Top := Edit2.Top;
Edit1.Parent.Insertcontrol(Edit2);
TWinControl(Edit1.parent).RemoveControl(Edit1);
Edit1.Free;
end;
将TEdit.Create替换为您想要使用的类,并像我一样复制您需要的所有属性,例如Left和Top。
这个更通用的程序可以与表单或框架一起使用(更新为使用新控件的子类):
function ReplaceControlEx(AControl: TControl; const AControlClass: TControlClass; const ANewName: string; const IsFreed : Boolean = True): TControl;
begin
if AControl = nil then
begin
Result := nil;
Exit;
end;
Result := AControlClass.Create(AControl.Owner);
CloneProperties(AControl, Result);// copy all properties to new control
// Result.Left := AControl.Left; // or copy some properties manually...
// Result.Top := AControl.Top;
Result.Name := ANewName;
Result.Parent := AControl.Parent; // needed for the InsertControl & RemoveControl magic
if IsFreed then
FreeAndNil(AControl);
end;
function ReplaceControl(AControl: TControl; const ANewName: string; const IsFreed : Boolean = True): TControl;
begin
if AControl = nil then
Result := nil
else
Result := ReplaceControlEx(AControl, TControlClass(AControl.ClassType), ANewName, IsFreed);
end;
procedure CloneProperties(const Source: TControl; const Dest: TControl);
var
ms: TMemoryStream;
OldName: string;
begin
OldName := Source.Name;
Source.Name := ''; // needed to avoid Name collision
try
ms := TMemoryStream.Create;
try
ms.WriteComponent(Source);
ms.Position := 0;
ms.ReadComponent(Dest);
finally
ms.Free;
end;
finally
Source.Name := OldName;
end;
end;
使用方法:
procedure TFrame1.AfterConstruction;
var
I: Integer;
NewEdit: TMyEdit;
begin
inherited;
NewEdit := ReplaceControlEx(Edit1, TMyEdit, 'Edit2') as TMyEdit;
if Assigned(NewEdit) then
begin
NewEdit.Text := 'My Brand New Edit';
NewEdit.Author := 'Myself';
end;
for I:=0 to ControlCount-1 do
begin
ShowMessage(Controls[I].Name);
end;
end;
注意:如果您正在Frame的AfterConstruction中进行此操作,请注意,主机Form的构造尚未完成。
在那里释放控件可能会导致许多问题,因为您正在干扰Form控件维护。
看看如果您尝试读取新的Edit Caption以在ShowMessage中显示会得到什么...
在这种情况下,您将想使用
...ReplaceControl(Edit1, 'Edit2', False)
然后再进行
...FreeAndNil(Edit1)
处理。
你实际上可以使用 RTTI(在 TypInfo 单元中查找)来克隆所有匹配的属性。我之前写过这方面的代码,但现在找不到了。我会继续寻找。