2008-09-23 34 views
7

是否有可能在运行时(例如,使用在实例化(有条件)实例化子类组件时替换和释放TEdit?如果是这样,应该如何以及何时应该完成?我试图将父级设置为零,并在窗体构造函数和AfterConstruction方法中调用free(),但在两种情况下,我都遇到了运行时错误。在运行时删除并替换可视组件


更具体地说,我得到了访问冲突错误(EAccessViolation)。看起来弗朗索瓦是正确的,当他表示通过表格控制家务解除了框架构造混乱的组件时。

回答

8

这更通用的日常工作或者与窗体或帧(更新为使用一个子类的新的控制):使用该程序的性能传递到新的控制

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; 

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 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; 

小心:如果您在框架的AfterConstruction内部执行此操作,请注意宿主窗体构造尚未完成。
释放控件在那里,可能会导致很多问题,因为你搞乱了Form控件管家。
看看你会得到什么,如果你尝试读取新编辑标题在ShowMessage显示...
在这种情况下,你可能需要使用
... ReplaceControl(EDIT1,“EDIT2”,
然后做一个
... FreeAndNil(Edit1)
以后。

8

您必须调用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做了所有的属性。

+0

为什么不设置Parent属性而不是InsertControl和RemoveControl? – 2008-09-23 20:38:28

+0

只是因为在这个问题上,它指出,父母财产不起作用。我记得我有一些使用InsertControl和RemoveControl编写的代码。所以我根本没有尝试Parent属性。 – Loesje 2008-09-24 08:33:58

+0

Loesje代码在TMyForm.AfterConstruction方法内工作,但不在TMyFrame.AfterConstruction中。与TFrame对象一起使用时,我应该在哪里放置它? – user16120 2008-09-23 18:39:27

1

您实际上可以使用RTTI(查看TypInfo单元)来克隆所有匹配的属性。我早就写了代码,但现在找不到它。我会继续寻找。