在运行时删除和替换可视组件 [英] Remove and Replace a visual component at runtime

查看:54
本文介绍了在运行时删除和替换可视组件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Is it possible to, for instance, replace and free a TEdit with a subclassed component instantiated (conditionally) at runtime? If so, how and when it should be done? I've tried to set the parent to nil and to call free() in the form constructor and AfterConstruction methods but in both cases I got a runtime error.

更具体地说,我遇到了访问冲突错误(EAccessViolation)。弗朗索瓦(François)似乎说对了,他说在框架构造中释放组件会与Form导致管理工作混乱。

Being more specific, I got an Access violation error (EAccessViolation). It seems François is right when he says that freeing components at frame costruction messes with Form controls housekeeping.

推荐答案

这个更通用的例程有效可以使用窗体或框架(已更新为使用新控件的子类):

This more generic routine works either with a Form or Frame (updated to use a subclass for the new control):

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;

使用此例程将属性传递给新控件

using this routine to pass the properties to the new control

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;

注意:如果在框架的AfterConstruction内部进行此操作,请注意,托管Form的构建尚未完成。

在那里释放控件,可能会导致很多问题,因为您搞不懂Form控件的内部管理。

看看您得到了什么如果您尝试读取新的Edit Caption以显示在ShowMessage中...

在这种情况下,您将要使用

... ReplaceControl(Edit1,'Edit2', False

,然后再执行

... FreeAndNil(Edit1)

之后。

CAUTION: If you are doing this inside the AfterConstruction of the Frame, beware that the hosting Form construction is not finished yet.
Freeing Controls there, might cause a lot of problems as you're messing up with Form controls housekeeping.
See what you get if you try to read the new Edit Caption to display in the ShowMessage...
In that case you would want to use
...ReplaceControl(Edit1, 'Edit2', False)
and then do a
...FreeAndNil(Edit1)
later.

这篇关于在运行时删除和替换可视组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆