Delphi 自定义GridPanel控件项问题

Delphi 自定义GridPanel控件项问题,delphi,delphi-10-seattle,Delphi,Delphi 10 Seattle,我正在将TGridPanel子类化到我的控件TMyGridPanel 我这样做是因为我想在GridPanel中添加4个默认按钮 因此,我覆盖构造函数,并创建如下按钮: constructor TMyGridPanel.Create(AOwner: TComponent); var i: Integer; btn: TButton; begin inherited Create(AOwner); for i := 0 to 3 do begin btn := TBut

我正在将
TGridPanel
子类化到我的控件
TMyGridPanel

我这样做是因为我想在
GridPanel
中添加4个默认按钮

因此,我覆盖
构造函数
,并创建如下按钮:

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
Items属性将4个按钮显示为
CollectionItems

现在我想复制并粘贴(复制)我的控件,因为我想有2个控件。 但是,当我这样做时,按钮不会显示在控件中

ControlCollection
Items属性显示4个集合项,但它们没有名称(空)。 当我关闭表单并重新打开它时,按钮就会出现

几天来,我一直在试图解决这个问题,但无法解决。

问题: 将面板组件复制到剪贴板时,其所有已发布的属性都将以流式方式显示为文本(将其粘贴到记事本中以查看其外观)

粘贴到表单将从此文本重新构造组件

由于
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
TCustomGridPanel
(类似于其他
TCustom…
组件)不发布其任何属性,因此它们不会流式传输到剪贴板

实际上,从
TCustom…
控件的变体继承,而不是从组件托盘中注册的变体继承,是组件子类化的正确方法

如果我们现在将此变体的
TMyGridPanel2
复制到剪贴板并粘贴到记事本中,我们可以看到没有其他属性:

object MyGridPanel21: TMyGridPanel2
  Left = 184
  Top = 200
  Width = 185
  Height = 41
end
缺点: 这种方法可行,但有几个缺点需要注意:

  • 您无法在对象检查器中访问由
    TGridPanel
    引入的自定义属性(但可以在运行时访问它们)。 在Object Inspector中恢复属性的一种解决方法是将其添加到组件的
    published
    部分:

    TMyGridPanel2 = class(TCustomGridPanel)
    public
        ...
    published
        property BorderStyle;
        property ColumnCollection;
        property RowCollection;
        ...
    end;
    
  • 您不能通过对象检查器更改四个按钮的属性,也不能将事件附加到它们。你必须在代码中这样做

    实际上,这是一种良好的行为。创建具有子控件的复合组件时,最好将所有功能都包含在组件本身中

完整代码示例:
首先在测试项目中尝试,而不是在生产中。

您说的是“名称”。原来的4个按钮有名字吗?动态创建的控件通常具有空名称属性,直到您指定了一个。你不是说“标题”吗?如果你已经覆盖了构造函数,那么我怀疑你没有覆盖OnCreate。这两个都不需要。@BlurrySterk name属性始终为空。但是,创建控件(而不是复制控件)时,集合项将显示为“MyGrid”。复制控件时,它不显示任何内容“”。我编辑了这篇文章并更正了OnCreate to Constructor。谢谢你的回答!
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.