复制时如何保持控件之间的连接?
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"代码。
我想问一下如何在复制控件时保留控件。例如,我有一个编辑框,可以用滑块控制值更改。当我使用此代码制作副本时,我获得了项目的副本,但滑块停止控制编辑框值。我该如何解决?
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"代码。