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

时间:2019-02-03 21:29:19

标签: 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.

如果我在测试组件上放一个按钮,结构将其显示为表单的一部分,而不是测试组件的子组件。...然后它仍然无法正常工作。

有没有办法做到这一点?

1 个答案:

答案 0 :(得分:2)

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

似乎必须重写基类中的两个过程才能更新控件。

第一个是称为“ 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.