【问题标题】:Is it possible for a sub-panel in a custom control to accept controls from the designer?自定义控件中的子面板是否可以接受来自设计器的控件?
【发布时间】:2019-06-27 16:47:56
【问题描述】:

我创建了一个继承自 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.

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

有没有办法做到这一点?

【问题讨论】:

    标签: delphi delphi-10.2-tokyo


    【解决方案1】:

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

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

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

    【讨论】:

      猜你喜欢
      • 2010-09-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-29
      • 1970-01-01
      • 2013-03-04
      相关资源
      最近更新 更多