代码之家  ›  专栏  ›  技术社区  ›  Andy k

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

  •  2
  • Andy k  · 技术社区  · 6 年前

    我创建了一个简单的测试控件,它继承了Tcustom控件,它包含两个面板。第一个是与顶部对齐的标题和与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 回复  |  直到 6 年前
        1
  •  2
  •   Andy k    6 年前

    经过大量的谷歌搜索,我找到了一些信息,这些信息使我能够拼凑出一个似乎有效的解决方案。

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

    第二个方法称为GetChildren,除了chm帮助中相当隐晦的文本之外,我找不到关于这个方法实际做什么的更多信息。然而,我根据我在web上发现的另一个示例改编了重写代码,该示例具有类似的需求,并且可以工作。因此,如果有人能够提供一些关于为什么这是必要的见解,那么这将是有用的信息。

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

    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.