复制时如何保持控件之间的连接?

how to retain connections between controls when copying?

我想问一下如何在复制控件时保留控件。例如,我有一个编辑框,可以用滑块控制值更改。当我使用此代码制作副本时,我获得了项目的副本,但滑块停止控制编辑框值。我该如何解决?

 TypInfo;

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 CloneEvents(Source, Dest: TControl);
var
 I: Integer;
 PropList: TPropList;
begin
 for I := 0 to GetPropList(Source.ClassInfo, [tkMethod], @PropList) - 1 do
   SetMethodProp(Dest, PropList[I], GetMethodProp(Source, PropList[I]));
end;

procedure DuplicateChildren(const ParentSource: TWinControl;
 const WithEvents: Boolean = True);
var
 I: Integer;
 CurrentControl, ClonedControl: TControl;
begin
 for I := ParentSource.ControlCount - 1 downto 0 do
 begin
   CurrentControl := ParentSource.Controls[I];
   ClonedControl := TControlClass(CurrentControl.ClassType).Create(CurrentControl.Owner);
   ClonedControl.Parent := ParentSource;
   CloneProperties(CurrentControl, ClonedControl);
   ClonedControl.Name := CurrentControl.Name + '_';
   if WithEvents then
     CloneEvents(CurrentControl, ClonedControl);
 end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 DuplicateChildren(Panel1);
end;

除非我误会了你,否则你的 CloneProperties 似乎与你提出的问题没有任何关系。在您的编辑控件 E1 和滑块 S1 的示例中,您可以克隆它们以生成 E2 和 S2,但是在您的代码中的某处必须有一条语句根据 S1 的值更改 E1 中的值。但是,按照您最有可能编写的方式,该声明不适用于 E2 和 S2。

最简单的解决方法是编写一个采用组件实例并将两者的操作链接在一起的方法。例如

  procedure TForm1.SetEditControlFromSlider(AnEdit : TEdit; ASlider : { TWhatever the slider actually is);
  begin
    // Set AnEdit's value from ASlider's properties
  end;

然后,你可以像这样用 Edit/Slider 对调用它

  SetEditControlFromSlider(E1, S1);
  [...]
  SetEditControlFromSlider(E2, S2);

我可以想象你可能不喜欢那样做。

IMO,最干净的解决方案是避免尝试完全克隆组件并创建一个包含编辑、滑块和连接它们的代码的 TFrame,然后根据需要将尽可能多的框架实例添加到您的表单中。就像从木头上掉下来一样简单。

type
  TEditFrame = class(TFrame)  // needs to be in its own unit, Used by your form
    Edit1: TEdit;
    TrackBar1: TTrackBar;
    procedure TrackBar1Change(Sender: TObject);
  private
  public
  end;
  [...]
  procedure TEditFrame.TrackBar1Change(Sender: TObject);
  begin
    Edit1.Text := IntToStr(TrackBar1.Position)
  end;

然后,您可以通过

将框架的克隆添加到 TForm1
  procedure TForm1.Button1Click(Sender: TObject);
  var
    AFrame : TEditFrame;
  begin
    Inc(FrameCount); // Field of TForm1
    AFrame := TEditFrame.Create(Self);
    AFrame.Name := AFrame.Name + IntToStr(FrameCount);
    AFrame.Parent := Self;
    AFrame.Top := AFrame.Height * FrameCount;
  end;

请注意,由于链接两个组件的代码 TrackBar1Change 已编译到框架单元中,因此您创建的框架的每个实例都会自动共享它,无需 "clone"代码。