2016-08-16 5 views
2

В Delphi я хочу создать новый элемент управления firemonkey, который будет содержать еще один элемент управления firemonkey. Это не проблема, потому что я могу сделать так:Firemonkey: Как определить компонент, содержащий другой компонент?

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

Но теперь я хотел бы, чтобы разрешить конечному пользователю modifie свойства FBtn в Object Inspector также! Я не знаю, как это сделать :(

если я удалю FBtn.stored: = False, то у меня будет в структуре explorer некоторый компонент с именем вроде < Компоненты [7]> и каждый раз, когда я сделаю просмотр форма в виде текста и обратно зрения как формы, то новый компонент появится в структуре проводника :(

+0

Попробуйте добавить FBtn.SetSubcomponent (true) в TMyComponent.Create. Прекрасно работает в VCL, должны работать в FireMonkey, тоже, если они не очень с ума ... –

+0

не это ничего не изменит, если я делать FBtn.SetSubcomponent (истина) я все равно будет иметь странное имя компонента в структуре проводника :(в каким-то образом FBtn.SetSubcomponent (правда) работают как FBtn.Stored ... – loki

ответ

3

Хотя ответ Реми технически будет работать, я не считал бы ей соответствующий подход. Это происходит потому, что, когда вы це ш любой TComponent потомок как свойство, это предполагает, что вы можете создать такой контроль внешне, а затем назначить его в инспекторе объектов. Конечно, вы не хотите, чтобы это произошло, поскольку этот элемент управления создан внутренне. Предполагается, что вы также хотите разрешить пользователю изменять определенные объекты, но не все.

Вместо этого я бы рекомендовал использовать 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. 
+0

Ваш класс 'TMyComponentButton' не реализует' Assign() '. –

+0

@remy да, это до op, чтобы решить, как реализовать. Просто заложим базовую концепцию. –

+0

как минимум вы можете показать, как реализовать его для созданных вами свойств. –

4

Все, что вы хотите, чтобы выставить в Objct инспектора должны быть объявлены в published собственности, например:

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; 
+0

спасибо это работа !! только один REMAK в инспекторе объектов у меня есть имя, как * MyComponent1. * ... можно иметь такое имя * MyComponent1.button1 * вместо этого для Exemple? это не очень важно, так или иначе – loki

+0

@loki, что вы описываете не имеет смысла. Просьба уточнить. –

+0

нет, это не нормально, жаль не заботиться :) – loki