【问题标题】:Moving controls between Delphi components在 Delphi 组件之间移动控件
【发布时间】:2019-10-17 04:02:36
【问题描述】:

我正在尝试创建一个可以容纳一些可视组件的 Delphi 非可视组件。

在设计时,我创建了一个自定义 TPanel,因此我可以将我的可视组件放入其中,然后我尝试从 TPanel 获取此控件并将它们存储在另一个组件中。

这是我的自定义面板

  TDesignTimePanel = class(TPanel)
  private
    FPanel: TPanelDialogo;
  public
    constructor Create(AOwner: TComponent); override;
    destructor  Destroy; override;

    procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
    function  GetChildOwner: TComponent; override;
  end

GetChildren 方法什么都不做,因为我不想在 DFM 文件中以传统方式编写此面板。 GetChildOwner 方法返回我希望存储可视控件的 TPanelDialogo。

这是我想要存储来自 TDesignTimePanel 的控件的组件

  TPanelDialogo = class(TComponent)
  private
    FDesignPanel: TDesignTimePanel;
    procedure VolcarFrameEnLista();
  public
    constructor Create(AOwner: TComponent); override;
    destructor  Destroy; override;
    function  CrearPanel(AOwner: TComponent): TPanel;
    procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
    function  GetChildOwner: TComponent; override;
  end;

我以这种方式创建自定义面板

function TPanelDialogo.CrearPanel(AOwner: TComponent): TPanel;
var
  i: integer;
  Componente : TControl;
begin
  if FDesignPanel = nil then
  begin
    FDesignPanel := TDesignTimePanel.Create(self);
    FDesignPanel.AsociarPanel( self );
  end;

  FDesignPanel.Name := Name + '_frame';
  FDesignPanel.Left := FX;
  // some other config
  FDesignPanel.Parent := Owner as TWinControl;

  FDesignPanel.Show;

  Result := FDesignPanel;
end;

所以我的 GetChildren 方法执行以下操作,其中 VolcarFrameEnLista 是我从 TDesignTimePanel 对象中获取控件并将它们存储在 TPanelDialogo 中的方法(FListaComponentes 是一个 TComponentList)

procedure TPanelDialogo.GetChildren(Proc: TGetChildProc; Root: TComponent);
var
  i: integer;
  OwnedComponent: TComponent;
begin
  if FDesignPanel <> nil then
  begin
    VolcarFrameEnLista();
    if Root = Self then
      for i := 0 to self.FListaComponentes.Count - 1 do
      begin
        OwnedComponent := FListaComponentes.Items[i];
        Proc(OwnedComponent);
      end;
  end;
end;

procedure TPanelDialogo.VolcarFrameEnLista( );
var
  i: integer;
  Componente: TControl;
begin
  for i := FDesignPanel.ControlCount - 1 downto 0 do
  begin
    Componente := FDesignPanel.Controls[i];
    if Pos( self.Name + '_', Componente.Name ) = 0 then
    begin
      Componente.Name := self.Name + '_' + Componente.Name;
    end;
    Componente.Parent := nil;
    if FListaComponentes.IndexOf(Componente) < 0 then
    begin
      FListaComponentes.Add( Componente );
    end;
  end;
end;

我希望我的 DFM 有这样的东西:

object Form1: TForm1
  object PanelDialogo1: TPanelDialogo
    Left = 712
    // ...
    object PanelDialogo1_Label1: TLabel
      Left = 88
      // ..
    end
    object PanelDialogo1_Label2: TLabel
      Left = 40
      // ..
    end
  end
end

但是我得到了这样的东西

object Form1: TForm1
  object PanelDialogo1: TPanelDialogo
    Left = 712
    // ...
  end
  object PanelDialogo1_Label1: TLabel
    Left = 88
    // ..
  end
  object PanelDialogo1_Label2: TLabel
    Left = 40
    // ..
  end
end

我应该怎么做才能让 TPanelDialogo 获得在 TDesignTimePanel 上绘制的组件的“所有权”。

【问题讨论】:

  • InsertComponent。不过乍一看不太对劲……
  • 已经试过了。 InsertComponent 失败:“名为 ... 的组件已存在”。但是,如果我尝试 RemoveComponent,那么该组件就会被破坏。
  • 别无选择,您必须插入到组件数组中才能更改所有权。名称必须是唯一的,请参阅文档。
  • 您要解决的实际问题是什么?为什么要将可视组件存储为非可视组件的子项? Delphi 的 dfm 存储与基于父/子的层次结构一起用于可视化组件。非可视组件始终具有作为父/所有者的表单,并且不能有子。
  • @R.Hoek - 我同意并且已经说过,设计看起来有问题,但 dfm 树并没有那么严格。菜单项 f.i. 覆盖 Get|SetParentComponent 以修改您描述的行为。

标签: windows delphi delphi-7


【解决方案1】:

我终于设法解决了我的问题。

我需要覆盖父对象上的 GetChildren 方法,这样我就可以将临时面板中的所有元素放入 TComponentList 中。然后我将这个列表的每个元素写入 DFM 文件。

在读取 DFM 文件时,我在 TPanelDialogo.Components 属性中获得了这些元素,但是由于 Delphi 环境中的重复控件,将这些元素存储在这里给我带来了麻烦。所以在 Loaded 方法上,我再次将所有这些组件放入 TComponentList 中。

这是代码

type

  TPanelDialogo = class;

  // especialización de Frame para pruebas
  TDesignTimePanel = class(TPanel)
  public
    constructor Create(AOwner: TComponent); override;
    destructor  Destroy; override;
    procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
  end;

  TPanelDialogo = class(TComponent)
  private
    FDesignPanel: TDesignTimePanel;
    FGENPant: TGENPant;

    FListaComponentes : TComponentList;

    procedure CerrarPanel;
    procedure VolcarFrameEnLista();
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;

    function CrearPanel(AOwner: TComponent): TPanel;
    procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
    function GetChildOwner: TComponent; override;
    procedure Loaded; override;

  published
    property ListaComponentes: TComponentList read FListaComponentes;
  end;

procedure Register;

implementation

uses
  ToolsApi,
  SysUtils, Graphics,
  Dialogs, StdCtrls,
  ComponentesGEN;

  { TDesignTimePanel }

constructor TDesignTimePanel.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
end;

destructor TDesignTimePanel.Destroy;
begin
  inherited;
end;

procedure TDesignTimePanel.GetChildren(Proc: TGetChildProc; Root: TComponent);
begin
  exit;
end;

constructor TPanelDialogo.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);

  FListaComponentes := TComponentList.Create(True);
end;

destructor TPanelDialogo.Destroy;
begin
  inherited Destroy;
end;

procedure TPanelDialogo.VolcarFrameEnLista( );
var
  i: integer;
  Componente: TControl;
  OwnerName, ParentName: string;
begin
  // recorrer el frame y rescatar sus componentes
  if FDesignPanel = nil then
    exit;
  for i := FDesignPanel.ControlCount - 1 downto 0 do
  begin
    Componente := FDesignPanel.Controls[i];
    if Componente.Owner <> nil then
      OwnerName := Componente.Owner.Name;
    if Componente.Parent <> nil then
      ParentName := Componente.Parent.Name;
    if Pos( self.Name + '_', Componente.Name ) = 0 then
    begin
      Componente.Name := self.Name + '_' + Componente.Name;
    end;
    if FListaComponentes.IndexOf(Componente) < 0 then
    begin
      FListaComponentes.Add( Componente );
    end;
  end;
end;

procedure TPanelDialogo.CerrarPanel;
begin
  if FDesignPanel = nil then Exit;

  FDesignPanel.Visible := false;
end;

function TPanelDialogo.GetChildOwner: TComponent;
begin
  Result := self;
end;

procedure TPanelDialogo.GetChildren(Proc: TGetChildProc; Root: TComponent);
var
  i: integer;
  OwnedComponent: TComponent;
begin
  if FDesignPanel <> nil then
  begin
    VolcarFrameEnLista();
    for i := 0 to self.FListaComponentes.Count - 1 do
    begin
      OwnedComponent := FListaComponentes.Items[i];
      Proc(OwnedComponent);
    end;
  end;
end;

function TPanelDialogo.CrearPanel(AOwner: TComponent): TPanel;
var
  i: integer;
  Componente : TControl;
begin
  if FDesignPanel = nil then
  begin
    FDesignPanel := TDesignTimePanel.Create(self);
    FDesignPanel.AsociarPanel( self );
  end;

  FDesignPanel.Name := Name + '_frame';
  // ...

  try
    for i := 0 to FListaComponentes.Count - 1 do
    begin
      Componente := FListaComponentes.Items[i] as TControl;
      Componente.Parent := FDesignPanel;
    end;
  finally
    FDesignPanel.Parent := Owner as TWinControl;
  end;

  FDesignPanel.Visible := true;

  Result := FDesignPanel;
end;

procedure TPanelDialogo.Loaded;
var
  i: integer;
  OwnedComponent: TComponent;
begin
  inherited;  
  for i := 0 to self.ComponentCount - 1 do
  begin
    OwnedComponent := self.Components[i];
    self.FListaComponentes.Add(OwnedComponent);
  end;  
  for i := self.ComponentCount - 1 downto 0 do
  begin
    OwnedComponent := self.Components[i];
    self.RemoveComponent(OwnedComponent);
  end;
  self.FLoaded := true;
end;

这是在设计时显示的:

这就是表单的 DFM

object Form1: TForm1
  ...
  object PanelDialogo1: TPanelDialogo
    ...
    object PanelDialogo1_Label2: TLabel
      Caption = 'Another label right here'
    end
    object PanelDialogo1_Label1: TLabel
      Caption = 'A label in the top of the panel'
    end
    object PanelDialogo1_Edit1: TEdit
      Text = 'Write something here...'
    end
    object PanelDialogo1_Panel1: TPanel
      object PanelDialogo1_Button1: TButton
        Caption = 'OK'
      end
    end
    object PanelDialogo1_Label3: TLabel
      Caption = 'Some label just here'
    end
  end
end

【讨论】:

    猜你喜欢
    • 2017-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-03
    • 1970-01-01
    • 2011-05-26
    • 1970-01-01
    相关资源
    最近更新 更多