Delphi Firemonkey:如何定义包含另一个组件的组件?

Delphi Firemonkey:如何定义包含另一个组件的组件?,delphi,firemonkey,Delphi,Firemonkey,在Delphi下,我想创建一个新的firemonkey控件,该控件将包含另一个firemonkey控件。这不是一个真正的问题,因为我可以这样做: constructor TMyComponent.Create(AOwner: TComponent); begin inherited; FBtn := Trectangle.create(self); FBtn.parent := self; FBtn.stored := false; end; 但是现在我想允许最终用户在对象检查

在Delphi下,我想创建一个新的firemonkey控件,该控件将包含另一个firemonkey控件。这不是一个真正的问题,因为我可以这样做:

constructor TMyComponent.Create(AOwner: TComponent);
begin
  inherited;
  FBtn := Trectangle.create(self);
  FBtn.parent := self;
  FBtn.stored := false;
end;
但是现在我想允许最终用户在对象检查器中修改FBtn的属性!我不知道怎么做:(


如果我删除FBtn.stored:=False,那么我将在结构资源管理器中有一些名为的组件,每次我都会以文本形式查看表单,然后返回以表单形式查看,那么结构资源管理器中将出现一个新组件:(

要在Objct检查器中公开的任何内容都必须在
已发布的
属性中声明,例如:

type
  TMyComponent = class(TComponent)
  private
    FBtn: TRectangle;
    procedure SetBtn(Value: TRectangle);
  published
    property Btn: TRectangle read FBtn write SetBtn;
  end;

constructor TMyComponent.Create(AOwner: TComponent);
begin
  inherited;
  FBtn := TRectangle.create(Self);
  FBtn.Parent := Self;
  FBtn.Stored := False;
  FBtn.SetSubComponent(True);
end;

procedure TMyComponent.SetBtn(Value: TRectangle);
begin
  FBtn.Assign(Value);
end;

虽然里米的回答在技术上是可行的,但我不认为它是合适的方法。这是因为当你发布任何<代码> TStuts<代码>子孙作为一个属性时,假定你会在外部创建这样的控件,然后在对象检查器中分配它。当然,你不想允许这种情况发生,因为控件是在内部创建的。您可能只希望允许用户更改某些属性,而不是所有属性

相反,我建议使用
TPersistent
,它只公开您实际希望提供访问权限的控件的那些属性

unit MyComponentUnit;

interface

uses
  System.Classes, System.SysUtils,
  Fmx.Controls, FMX.StdCtrls, FMX.Objects;

type
  TMyComponentButton = class(TPersistent)
  private
    FBtn: TRectangle;
    function GetXRadius: Single;
    function GetYRadius: Single;
    procedure SetXRadius(const Value: Single);
    procedure SetYRadius(const Value: Single);
    //And any other property getters/setters you wish to wrap
  public
    constructor Create(ABtn: TRectangle);
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
  published
    property XRadius: Single read GetXRadius write SetXRadius;
    property YRadius: Single read GetYRadius write SetYRadius;
    //And any other properties you wish to wrap
  end;

  TMyComponent = class(TControl)
  private
    FBtn: TRectangle;
    FMyComponentButton: TMyComponentButton;
    procedure SetMyComponentButton(const Value: TMyComponentButton);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property MyComponentButton: TMyComponentButton
      read FMyComponentButton write SetMyComponentButton;
  end;

implementation

{ TMyComponentButton }

constructor TMyComponentButton.Create(ABtn: TRectangle);
begin
  inherited Create;
  FBtn:= ABtn;
end;

destructor TMyComponentButton.Destroy;
begin

  inherited;
end;

procedure TMyComponentButton.Assign(Source: TPersistent);
begin
  if Source is TMyComponentButton then begin
    XRadius:= (Source as TMyComponentButton).XRadius;
    YRadius:= (Source as TMyComponentButton).YRadius;
    //And everything else you need to assign
  end else
    inherited;
end;

function TMyComponentButton.GetXRadius: Single;
begin
  Result:= FBtn.XRadius;
end;

function TMyComponentButton.GetYRadius: Single;
begin
  Result:= FBtn.YRadius;
end;

procedure TMyComponentButton.SetXRadius(const Value: Single);
begin
  FBtn.XRadius:= Value;
end;

procedure TMyComponentButton.SetYRadius(const Value: Single);
begin
  FBtn.YRadius:= Value;
end;

{ TMyComponent }

constructor TMyComponent.Create(AOwner: TComponent);
begin
  inherited;
  FBtn:= TRectangle.Create(Self);
  FBtn.Parent:= Self;
  FBtn.Stored:= False;
  FMyComponentButton:= TMyComponentButton.Create(FBtn);
end;

destructor TMyComponent.Destroy;
begin
  FreeAndNil(FMyComponentButton);
  FreeAndNil(FBtn);
  inherited;
end;

procedure TMyComponent.SetMyComponentButton(const Value: TMyComponentButton);
begin
  FMyComponentButton.Assign(Value);
end;

end.

尝试在TMyComponent.Create中添加FBtn.SetSubcomponent(true)。在vcl中工作良好,在firemonkey中也应该工作,如果他们不是非常疯狂的话……不是的,如果我使用FBtn.SetSubcomponent,没有任何改变‌​(true)在结构资源管理器中我仍然会有奇怪的组件名称:(以某种方式FBtn.SetSubcomponent‌​(true)像FBtn.Stored一样工作……您的
TMyComponentButton
类未实现
Assign()
@remy是的,这取决于op来决定如何实现。只需奠定基本概念。你至少可以展示如何为你创建的属性实现它。属性不必公开外部类。想想TFont等。谢谢它的工作!!在对象检查器中只需一个remak,我的名字像MyComponent 1…是p吗例如,是否可以改用MyComponent 1.button1这样的名称?这并不重要anyway@loki你所描述的没有意义。请澄清。雷米,如果我在“事件”选项卡上尝试向收到的子组件添加事件,我知道我想用你的方法(看起来正是我想要的)说什么“无法为未命名组件创建方法”:(当然不是,因为子组件的
Name
属性尚未分配值。您确实不应该向用户公开子组件的事件。主组件应该为子组件的事件分配自己的处理程序,然后主组件可以向用户公开自己的事件。