自定义 GridPanel ControlItems 问题
Custom GridPanel ControlItems Issue
我正在将 TGridPanel
子类化到我的控件 TMyGridPanel
。
我这样做是因为我想在 GridPanel
.
中添加 4 个默认按钮
所以我重写 constructor
并创建如下按钮:
constructor TMyGridPanel.Create(AOwner: TComponent);
var
i: Integer;
btn: TButton;
begin
inherited Create(AOwner);
for i := 0 to 3 do
begin
btn := TButton.Create(Self);
btn.Parent := Self;
btn.Align := alClient;
btn.Caption := 'Hello World';
btn.Visible := True;
end;
end;
这工作正常。
ControlCollection
项 属性 显示 4 个按钮 CollectionItems
.
现在我想复制并粘贴(复制)我的控件,因为我想要其中的 2 个。
但是,当我这样做时,按钮不会出现在控件中。
ControlCollection
项 属性 显示 4 Collection 项,但它们没有名称(空)。
当我关闭表单并重新打开它时,会出现按钮。
我已经尝试解决这个问题好几天了,但还是搞不明白。
问题:
当您将面板组件复制到剪贴板时,其所有已发布的属性都会流式传输到文本中(将其粘贴到记事本中以查看其外观)。
粘贴到表单会从该文本重建组件。
并且由于 ControlCollection
属性 在 Vcl.ExtCtrls.TGridPanel
中定义为 published
,其中的按钮包含在本文中。以下是摘录:
object MyGridPanel1: TMyGridPanel
Left = 64
...
ControlCollection = <
item
Column = 0
Control = Button9
Row = 0
end
item
Column = 1
Control = Button10
Row = 0
end
...
object Button9: TButton
Left = 1
...
end
object Button10: TButton
Left = 92
...
end
...
end
粘贴时,IDE设计者先新建一个class对象TMyGridPanel
。在此步骤中,TMyGridPanel
的构造函数创建了一组新按钮。
之后所有已发布的属性都从文本中重建,包括其中的 ControlCollection 和 Buttons,这就是问题所在。
可能的解决方案:
在这种情况下可能的解决方案是将 TMyGridPanel
的父级 class 更改为 TCustomGridPanel
TMyGridPanel2 = class(TCustomGridPanel)
...
TCustomGridPanel
(类似于其他 TCustom...
组件)不会发布其任何属性,因此它们不会流式传输到剪贴板。
实际上继承 TCustom...
控件的变体,而不是从 Component Pallet 中注册的控件继承,才是子class 组件的正确方法。
如果我们现在将 TMyGridPanel2
的这个变体复制到剪贴板并将其粘贴到记事本中,我们可以看到没有其他属性:
object MyGridPanel21: TMyGridPanel2
Left = 184
Top = 200
Width = 185
Height = 41
end
缺点:
这种方法有效,但有几个必须注意的缺点:
您无法在对象检查器中访问 TGridPanel
引入的自定义属性(但您可以在运行时访问它们)。
将 属性 带回对象检查器的解决方法是将其添加到组件的 published
部分:
TMyGridPanel2 = class(TCustomGridPanel)
public
...
published
property BorderStyle;
property ColumnCollection;
property RowCollection;
...
end;
您不能通过对象检查器更改四个按钮的属性,也不能为它们附加事件。您必须在代码中执行此操作。
其实这是很好的行为。当您创建具有子控件的复合组件时,最好将所有功能都包含在组件本身中。
完整代码示例:
unit MyGridPanel2;
interface
uses
Classes, Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.Controls;
type
TMyGridPanel2 = class(TCustomGridPanel)
private
public
constructor Create(AOwner: TComponent); override;
published
end;
procedure Register;
implementation
{ TMyGridPanel2 }
constructor TMyGridPanel2.Create(AOwner: TComponent);
var
i: Integer;
btn: TButton;
begin
inherited Create(AOwner);
for i := 0 to 3 do
begin
btn := TButton.Create(Self);
btn.Parent := Self;
btn.Align := alClient;
btn.Caption := 'Hello World';
btn.Visible := True;
end;
end;
procedure Register;
begin
RegisterComponents('Custom', [TMyGridPanel2]);
end;
end.
首先在测试项目中尝试这个,而不是在生产中。
我正在将 TGridPanel
子类化到我的控件 TMyGridPanel
。
我这样做是因为我想在 GridPanel
.
所以我重写 constructor
并创建如下按钮:
constructor TMyGridPanel.Create(AOwner: TComponent);
var
i: Integer;
btn: TButton;
begin
inherited Create(AOwner);
for i := 0 to 3 do
begin
btn := TButton.Create(Self);
btn.Parent := Self;
btn.Align := alClient;
btn.Caption := 'Hello World';
btn.Visible := True;
end;
end;
这工作正常。
ControlCollection
项 属性 显示 4 个按钮 CollectionItems
.
现在我想复制并粘贴(复制)我的控件,因为我想要其中的 2 个。 但是,当我这样做时,按钮不会出现在控件中。
ControlCollection
项 属性 显示 4 Collection 项,但它们没有名称(空)。
当我关闭表单并重新打开它时,会出现按钮。
我已经尝试解决这个问题好几天了,但还是搞不明白。
问题:
当您将面板组件复制到剪贴板时,其所有已发布的属性都会流式传输到文本中(将其粘贴到记事本中以查看其外观)。
粘贴到表单会从该文本重建组件。
并且由于 ControlCollection
属性 在 Vcl.ExtCtrls.TGridPanel
中定义为 published
,其中的按钮包含在本文中。以下是摘录:
object MyGridPanel1: TMyGridPanel
Left = 64
...
ControlCollection = <
item
Column = 0
Control = Button9
Row = 0
end
item
Column = 1
Control = Button10
Row = 0
end
...
object Button9: TButton
Left = 1
...
end
object Button10: TButton
Left = 92
...
end
...
end
粘贴时,IDE设计者先新建一个class对象TMyGridPanel
。在此步骤中,TMyGridPanel
的构造函数创建了一组新按钮。
之后所有已发布的属性都从文本中重建,包括其中的 ControlCollection 和 Buttons,这就是问题所在。
可能的解决方案:
在这种情况下可能的解决方案是将 TMyGridPanel
的父级 class 更改为 TCustomGridPanel
TMyGridPanel2 = class(TCustomGridPanel)
...
TCustomGridPanel
(类似于其他 TCustom...
组件)不会发布其任何属性,因此它们不会流式传输到剪贴板。
实际上继承 TCustom...
控件的变体,而不是从 Component Pallet 中注册的控件继承,才是子class 组件的正确方法。
如果我们现在将 TMyGridPanel2
的这个变体复制到剪贴板并将其粘贴到记事本中,我们可以看到没有其他属性:
object MyGridPanel21: TMyGridPanel2
Left = 184
Top = 200
Width = 185
Height = 41
end
缺点:
这种方法有效,但有几个必须注意的缺点:
您无法在对象检查器中访问
TGridPanel
引入的自定义属性(但您可以在运行时访问它们)。 将 属性 带回对象检查器的解决方法是将其添加到组件的published
部分:TMyGridPanel2 = class(TCustomGridPanel) public ... published property BorderStyle; property ColumnCollection; property RowCollection; ... end;
您不能通过对象检查器更改四个按钮的属性,也不能为它们附加事件。您必须在代码中执行此操作。
其实这是很好的行为。当您创建具有子控件的复合组件时,最好将所有功能都包含在组件本身中。
完整代码示例:
unit MyGridPanel2;
interface
uses
Classes, Vcl.StdCtrls, Vcl.ExtCtrls, Vcl.Controls;
type
TMyGridPanel2 = class(TCustomGridPanel)
private
public
constructor Create(AOwner: TComponent); override;
published
end;
procedure Register;
implementation
{ TMyGridPanel2 }
constructor TMyGridPanel2.Create(AOwner: TComponent);
var
i: Integer;
btn: TButton;
begin
inherited Create(AOwner);
for i := 0 to 3 do
begin
btn := TButton.Create(Self);
btn.Parent := Self;
btn.Align := alClient;
btn.Caption := 'Hello World';
btn.Visible := True;
end;
end;
procedure Register;
begin
RegisterComponents('Custom', [TMyGridPanel2]);
end;
end.
首先在测试项目中尝试这个,而不是在生产中。