delphi - 自定义控件中的子面板是否可以接受设计器的控件?

标签 delphi delphi-10.2-tokyo

我创建了一个继承自 Tcustom 控件的简单测试控件,其中包含 2 个面板。第一个是与顶部对齐的标题和与 alclient 对齐的客户端面板。

我希望客户端面板接受来自设计器的控件,虽然我可以将控件放置在面板上,但它们在运行时不可见,并且在项目关闭时无法正确保存。

该控件的示例代码如下

unit Testcontrol;

interface
uses Windows,System.SysUtils, System.Classes,System.Types, Vcl.Controls,
     Vcl.Forms,Vcl.ExtCtrls,graphics,Messages;

type
  TtestControl = class(TCustomControl)
  private
    FHeader:Tpanel;
    FClient:Tpanel;
  protected
  public
    constructor Create(Aowner:Tcomponent);override;
    destructor Destroy;override;
  published
    property Align;
  end;

implementation

{ TtestControl }

constructor TtestControl.Create(Aowner: Tcomponent);
begin
  inherited;
  Fheader:=Tpanel.create(self);
  Fheader.Caption:='Header';
  Fheader.Height:=20;
  Fheader.Parent:=self;
  Fheader.Align:=altop;
  Fclient:=Tpanel.Create(Self);
  with Fclient do
  begin
    setsubcomponent(true);
    ControlStyle := ControlStyle + [csAcceptsControls];
    Align:=alclient;
    Parent:=self;
    color:=clwhite;
    BorderStyle:=bssingle;
    Ctl3D:=false;
    ParentCtl3D:=false;
    Bevelouter:=bvnone;
  end;
end;

destructor TtestControl.Destroy;
begin
  FHeader.Free;
  FClient.Free;
  inherited;
end;

end.

如果我在测试组件上放置一个按钮,结构会将其显示为表单的一部分,而不是测试组件的子组件......然后它就不起作用了。

有办法做到这一点吗?

最佳答案

经过大量谷歌搜索后,我发现了一些信息,这些信息使我能够拼凑出一个似乎可行的解决方案。

似乎需要重写基类中的两个过程来更新控件。

第一个是名为“Loaded”的方法,该方法在流传输结束时调用。

流式传输似乎将设计者放置的所有子面板组件放置在基本组件上,而不是放置在它们最初父级的面板上。因此,此例程在加载过程完成后手动重新分配 Parent 属性。

第二种方法称为 GetChildren,除了 chm 帮助中相当神秘的文本之外,我找不到太多关于该方法实际用途的信息。不过,我从网上找到的另一个示例中改编了重写的代码,该示例具有类似的要求并且有效。因此,如果任何人都可以提供一些关于为什么这是必要的见解,那么这将是有用的信息。

我已经粘贴了下面示例自定义组件的完整源代码,以便将来有类似需求的任何人都可以将其用作自己组件的起始模板。

unit Testcontrol;

interface
uses Windows, System.Classes, Vcl.Controls, Vcl.Forms, Vcl.ExtCtrls,graphics;

type
  TtestControl = class(TCustomControl)
  private
    FHeader:Tpanel;
    FClient:Tpanel;
  protected
    procedure Loaded;override;
    procedure GetChildren(Proc:TGetChildProc; Root:TComponent);override;
  public
    constructor Create(Aowner:Tcomponent);override;
    destructor Destroy;override;
  published
    property Align;
  end;

implementation

{ TtestControl }

constructor TtestControl.Create(Aowner:Tcomponent);
begin
  inherited;
  Fheader:=Tpanel.create(self);
  Fheader.setsubcomponent(true);
  Fheader.Caption:='Header';
  Fheader.Height:=20;
  Fheader.Parent:=self;
  Fheader.Align:=altop;
  Fclient:=Tpanel.Create(Self);
  with Fclient do
  begin
    setsubcomponent(true);
    ControlStyle := ControlStyle + [csAcceptsControls];
    Align:=alclient;
    Parent:=self;
    color:=clwhite;
    BorderStyle:=bssingle;
    Ctl3D:=false;
    ParentCtl3D:=false;
    Bevelouter:=bvnone;
  end;
end;

destructor TtestControl.Destroy;
begin
  FHeader.Free;
  FClient.Free;
  inherited;
end;

procedure TtestControl.Loaded;
var i:integer;
begin
  inherited;
  for i := ControlCount - 1 downto 0 do
   if (Controls[i] <> Fheader) and (Controls[i] <> Fclient) then
     Controls[i].Parent := Fclient;
end;

procedure TtestControl.GetChildren(Proc:TGetChildProc; Root:TComponent);
var i:integer;
begin
  inherited;
  for i := 0 to Fclient.ControlCount-1 do
    Proc(Fclient.Controls[i]);
end;

end.

关于delphi - 自定义控件中的子面板是否可以接受设计器的控件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54507778/

相关文章:

delphi - 我应该将许可证数据存储在本地哪里?

delphi - 如何将 MenuItemExecute() 与 AVDoc.OpenInWindowEx() 一起使用

delphi - 如何使用 FireDAC 设置 Firebird (InterBase) 的事务锁定超时?

Delphi - 在 OSX 上检查 Dropbox

sql - 将数据插入数据库[Delphi]

multithreading - 使用 AnonymousThread 将值传递给 onTerminate

android - Delphi Android 应用程序 API 级别 26?

delphi - TWICImage : How to overlay transparent PNG on JPG?

delphi - 泛型类中的内部 const 似乎不是由编译器计算的

delphi - 删除IDE代码编辑器中间的垂直白线