Firemonkey: How to define a component that contain another component?

让人想犯罪 __ 提交于 2019-12-20 03:16:20

问题


Under Delphi, i want to create a new firemonkey control that will contain another firemonkey control. This is not really a problem because i can do like this :

constructor TMyComponent.Create(AOwner: TComponent);
begin
  inherited;
  FBtn := Trectangle.create(self);
  FBtn.parent := self;
  FBtn.stored := false;
end;

But now i would like to permit end-user to modifie the properties of the FBtn in the Object Inspector also! i don't know how to do :(

if i remove the FBtn.stored := False then i will have in the structure explorer some component with name like < Components[7] > and every time i will do view the form as text and back to view as form then a new component will appear in the structure explorer :(


回答1:


While Remy's answer technically will work, I wouldn't consider it the appropriate approach. This is because when you publish any TComponent descendant as a property, this presumes that you would create such a control externally and then assign it within the object inspector. Surely you don't want to allow this to happen, since this control is created internally. You also presumably only want to allow the user to change certain properties, not all of them.

Instead, I would recommend using a TPersistent which exposes only those properties of the control you actually want to provide access to.

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.



回答2:


Anything you want to expose in the Objct Inspector must be declared in a published property, eg:

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;


来源:https://stackoverflow.com/questions/38985078/firemonkey-how-to-define-a-component-that-contain-another-component

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!