Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a dialog like component that allows drop other controls inside it?

It is a Firemonkey component, however I could see that most of the component base is the same for VCL and FMX, so please if you know how to do that in VCL share your knowledge, it can be eventually the solution for my case.

I am using a TPopup as the ancestor. It is convenient for me since it remains on the form/frame and I can wire it with LiveBindings using the same context/structure of the parent, this is very convenient for me.

I need it behave exactly it is the TPopup, as a container. But I need it looks better and have my specific buttons (I have created some properties and automations for my software inside it)

The problem is that I create some internal controls, like TLayouts, Tpanels and Tbuttons to make looks like this: (empty)

My empty Popup

That black area inside it is where I want to drop controls like TEdit and others.

I have set all the internal created controls to Store = false, so it is not getting stored on the streaming system. Doing that when I drop a TEdit for example, what I get is this (Tedit with aligned=top I need this):

My Popup with TEdit

However I was expecting this:

My popup with TEdit in the right position

If I change the Store = true I can get the right effect, but all the inside controls are exposed on the Structure panel and every time I save the form and reopen everything gets duplicated. The inside components exposed is not a problem for me, but the duplication is, if I close and open the component 10 times I will get the entire inside structure replicated 10 time.

I will try to show some code that is related to the design of the component:

Class declaration:

  [ComponentPlatformsAttribute(pidWin32 or pidWin64 or pidOSX32 or pidiOSSimulator or pidiOSDevice or pidAndroid)]   TNaharFMXPopup = class(TPopup, INaharControlAdapter, INaharControl)   private   protected     FpnlMain       : TPanel;     FlytToolBar    : TLayout;     FbtnClose      : TButton;     FbtnSave       : TButton;     FbtnEdit       : TButton;     FpnlClientArea : TPanel;     FlblTitle      : TLabel;     procedure   Loaded; override;     procedure   Notification(AComponent: TComponent; Operation: TOperation); override;  constructor Create:      constructor TNaharFMXPopup.Create(AOwner: TComponent);     begin       inherited;        FpnlMain         := TPanel.Create(Self);       FlblTitle        := TLabel.Create(Self);       FlytToolBar      := TLayout.Create(Self);       FbtnEdit         := TButton.Create(Self);       FpnlClientArea   := TPanel.Create(Self);       FbtnClose         := TButton.Create(FlytToolBar);       FbtnSave          := TButton.Create(FlytToolBar);        Height         := 382;       Placement      := TPlacement.Center;       StyleLookup    := 'combopopupstyle';       Width          := 300;        ApplyControlsProp;      end; 

Setting properties of the internal controls:

procedure TNaharFMXPopup.ApplyControlsProp; begin   with FpnlMain do   begin     Parent         := Self;     Align          := TAlignLayout.Client;     StyleLookup    := 'grouppanel';     TabOrder       := 0;     Margins.Bottom := 10;     Margins.Left   := 10;     Margins.Right  := 10;     Margins.Top    := 10;     Stored         := false;   end;   with FlblTitle do   begin     Parent         := FpnlMain;     Text           := 'Título';     Align          := TAlignLayout.Top;     Height         := 36;     StyleLookup    := 'flyouttitlelabel';     Stored         := false;   end;   with FpnlClientArea do   begin     Parent         := FpnlMain;     Align          := TAlignLayout.Client;     StyleLookup    := 'gridpanel';     TabOrder       := 0;     Margins.Bottom := 5;     Margins.Left   := 5;     Margins.Right  := 5;     Margins.Top    := 5;     Stored         := false;   end;   with FlytToolBar do   begin     Parent         := FpnlMain;     Align          := TAlignLayout.Bottom;     Height         := 50;     Stored         := false;   end;   with FbtnClose do   begin     Parent         := FlytToolBar;     Text           := 'Fecha';     Align          := TAlignLayout.Left;     Height         := 50;     StyleLookup    := 'tilebutton';     TabOrder       := 0;     Width          := 70;     ModalResult    := mrClose;     Stored         := false;   end;   with FbtnEdit do   begin     Parent         := FlytToolBar;     Text           := '';//'Edita';     Align          := TAlignLayout.Left;     Height         := 50;     StyleLookup    := 'tilebutton';     TabOrder       := 1;     Width          := 70;     ModalResult    := mrContinue;     Stored         := false;     Enabled        := false;   end;   with FbtnSave do   begin     Parent         := FlytToolBar;     Text           := 'Salva';     Align          := TAlignLayout.Left;     Height         := 50;     StyleLookup    := 'tilebutton';     TabOrder       := 2;     Width          := 70;     ModalResult    := mrOk;     Stored         := false;   end; end; 

Loaded:

procedure TNaharFMXPopup.Loaded; begin   inherited;    ApplyControlsProp;   SetEvents; end; 

I have tried the following with notification, trying to make the inserted control a parent for my intenal "clientarea"

procedure TNaharFMXPopup.Notification(AComponent: TComponent; Operation: TOperation); begin   inherited;   if (Operation = opInsert) and (csDesigning in ComponentState) then   begin     if AComponent.Owner = self then       if AComponent is TFmxObject then       begin         (AComponent as TFmxObject).Parent := FpnlClientArea;       end;   end;  end; 

But that made nothing change.

I have asked similar question before, but I was not aware of many things on creating such a component and the answer I got gave little help, I was missing the Parent of each internal component.

Now I am trying to really show where is my need: I need to drop controls on my TPopup dialog that will be parented of the ClientArea inside it.

like image 905
Eduardo Elias Avatar asked Jul 27 '14 16:07

Eduardo Elias


People also ask

What are the 3 main types of dialog boxes?

There are 3 types of dialog boxes: modeless, modal, and system modal. Modal dialog boxes are generally used inside a program, to display messages, and to set program parameters.

How do you create a dialog?

To create a new dialog box In Resource View, right-click your . rc file and select Add Resource. In the Add Resource dialog box, select Dialog in the Resource Type list, then choose New. If a plus sign (+) appears next to the Dialog resource type, it means that dialog box templates are available.


1 Answers

Take a closer look at TTabControl / TTabItem in the unit FMX.TabControl. This is your perfect example because it basically needs to solve the same problem.

The following function is what you need to override:

procedure DoAddObject(const AObject: TFmxObject); override; 

This is called when a control is added to your control. Override this function so that your control is added to the FpnlClientArea control instead. You'd get something similar to this:

procedure TNaharFMXPopup.DoAddObject(const AObject: TFmxObject); // ... begin   if (FpnlClientArea <> nil) and not AObject.Equals(FpnlClientArea) and not AObject.Equals(ResourceLink) then   begin     FpnlClientArea.AddObject(AObject);   end   else     inherited; end; 

Make sure that AObject.Equals also excludes your other "not stored" controls.

Without the DoAddObject override, the FMX TabControl would show the same problem as your component currently has.


The TPopup is not intended to accept controls. So that needs a few more tricks. Here's a modified version of your unit that works for me. I've added a few comments:

unit NaharFMXPopup;  interface  uses   System.UITypes,   System.Variants,   System.SysUtils, System.Classes, FMX.Types, FMX.Controls, FMX.Layouts, FMX.StdCtrls;  type   [ComponentPlatformsAttribute(pidWin32 or pidWin64 or pidOSX32 or pidiOSSimulator or pidiOSDevice or pidAndroid)]   TNaharFMXPopup = class(TPopup)   private     procedure   ApplyControlsProp;   protected     FpnlMain       : TPanel;     FlytToolBar    : TLayout;     FbtnClose      : TButton;     FbtnSave       : TButton;     FbtnEdit       : TButton;     FpnlClientArea : TContent; // change to TContent.      // For TPanel we'd have to call SetAcceptControls(False),      // but that is not easily possible because that is protected     FlblTitle      : TLabel;     procedure   Loaded; override;     procedure   Notification(AComponent: TComponent; Operation: TOperation); override;     procedure   DoAddObject(const AObject: TFmxObject); override;   public     procedure   InternalOnClose(Sender: TObject);     procedure   InternalOnSave(Sender: TObject);     procedure   InternalOnEdit(Sender: TObject);     constructor Create(AOwner: TComponent); override;     destructor  Destroy; override;     procedure   SetEvents;   published   end;  implementation   { TNaharFMXPopup }  constructor TNaharFMXPopup.Create(AOwner: TComponent); begin   inherited;    FpnlMain         := TPanel.Create(Self);   FlblTitle        := TLabel.Create(Self);   FlytToolBar      := TLayout.Create(Self);   FbtnEdit         := TButton.Create(Self);   FpnlClientArea   := TContent.Create(Self); // change to TContent   FbtnClose         := TButton.Create(FlytToolBar);   FbtnSave          := TButton.Create(FlytToolBar);    Height         := 382;   Placement      := TPlacement.Center;   StyleLookup    := 'combopopupstyle';   Width          := 300;    // A TPopup is not intended to accept controls   // so we have to undo those restrictions:   Visible := True;   SetAcceptsControls(True);    ApplyControlsProp; end;  destructor TNaharFMXPopup.Destroy; begin    inherited; end;  procedure TNaharFMXPopup.ApplyControlsProp; begin   with FpnlMain do   begin     Parent         := Self;     Align          := TAlignLayout.Bottom;     StyleLookup    := 'grouppanel';     TabOrder       := 0;     Height         := 50;     Margins.Bottom := 10;     Margins.Left   := 10;     Margins.Right  := 10;     Margins.Top    := 10;     Stored         := false;   end;   with FpnlClientArea do   begin     Parent         := Self; // we have to change this to Self (it refuses working if the parent is FPnlMain)     Align          := TAlignLayout.Client;     Margins.Left   := 3;     Margins.Right  := 3;     Margins.Top    := 3;     Margins.Bottom := 3;     Stored         := false;   end;   with FlytToolBar do   begin     Parent         := FpnlMain;     Align          := TAlignLayout.Bottom;     Height         := 50;     Stored         := false;   end;   with FbtnClose do   begin     Parent         := FlytToolBar;     Text           := 'Close';     Align          := TAlignLayout.Left;     Height         := 50;     StyleLookup    := 'tilebutton';     TabOrder       := 0;     Width          := 70;     ModalResult    := mrClose;     Stored         := false;   end;   with FbtnEdit do   begin     Parent         := FlytToolBar;     Text           := '';//'Edita';     Align          := TAlignLayout.Left;     Height         := 50;     StyleLookup    := 'tilebutton';     TabOrder       := 1;     Width          := 70;     ModalResult    := mrContinue;     Stored         := false;     Enabled        := false;   end;   with FbtnSave do   begin     Parent         := FlytToolBar;     Text           := 'Save';     Align          := TAlignLayout.Left;     Height         := 50;     StyleLookup    := 'tilebutton';     TabOrder       := 2;     Width          := 70;     ModalResult    := mrOk;     Stored         := false;   end; end;  procedure TNaharFMXPopup.Loaded; begin   inherited;    ApplyControlsProp; //  SetEvents;  end;  procedure TNaharFMXPopup.Notification(AComponent: TComponent;   Operation: TOperation); begin   inherited;  end;  procedure TNaharFMXPopup.InternalOnClose(Sender: TObject); begin end;  procedure TNaharFMXPopup.InternalOnEdit(Sender: TObject); begin end;  procedure TNaharFMXPopup.InternalOnSave(Sender: TObject); begin end;  procedure TNaharFMXPopup.SetEvents; begin   FbtnClose.OnClick := InternalOnClose;   FbtnSave.OnClick := InternalOnSave;   FbtnEdit.OnClick := InternalOnEdit; end;   procedure TNaharFMXPopup.DoAddObject(const AObject: TFmxObject); begin //inherited; try commenting the block bellow and uncommenting this one //Exit;    if (FpnlClientArea <> nil)     and not AObject.Equals(FpnlClientArea)     and not AObject.Equals(ResourceLink)     and not AObject.Equals(FpnlMain)     and not AObject.Equals(FlblTitle)     and not AObject.Equals(FlytToolBar)     and not AObject.Equals(FbtnEdit)     and not AObject.Equals(FpnlClientArea)     and not AObject.Equals(FbtnClose)     and not AObject.Equals(FbtnSave) then    begin     FpnlClientArea.AddObject(AObject);   end   else     inherited; end;  end. 
like image 64
Sebastian Z Avatar answered Oct 09 '22 04:10

Sebastian Z