delphi - vendedor - ¿Cómo crear un diálogo como un componente que permita soltar otros controles dentro de él?
dialogo entre vendedor y cliente en ingles (2)
Es un componente de Firemonkey, sin embargo, pude ver que la mayor parte de la base de componentes es la misma para VCL y FMX, así que si saben cómo hacer eso en VCL compartan sus conocimientos, eventualmente puede ser la solución para mi caso.
Estoy usando un TPopup como antepasado. Es conveniente para mí, ya que permanece en el formulario / marco y puedo conectarlo con LiveBindings usando el mismo contexto / estructura del elemento principal, esto es muy conveniente para mí.
Necesito que se comporte exactamente, es el TPopup, como un contenedor. Pero necesito que se vea mejor y tenga mis botones específicos (he creado algunas propiedades y automatizaciones para mi software dentro de él)
El problema es que creo algunos controles internos, como TLayouts, Tpanels y Tbuttons para que se vea así: (vacío)
Esa área negra dentro de ella es donde quiero soltar controles como TEdit y otros.
He configurado todos los controles internos creados en Store = false, por lo que no se almacenan en el sistema de transmisión. Al hacer eso cuando dejo caer un TEdit por ejemplo, lo que obtengo es esto (Tedit con alineado = arriba lo necesito):
Sin embargo, yo estaba esperando esto:
Si cambio Store = true, puedo obtener el efecto correcto, pero todos los controles internos están expuestos en el panel de Estructura y cada vez que guardo el formulario y vuelvo a abrir todo se duplica. Los componentes internos expuestos no son un problema para mí, pero la duplicación es que, si cierro y abro el componente 10 veces, haré que toda la estructura interna se repita 10 veces.
Trataré de mostrar algún código relacionado con el diseño del componente:
Declaración de clase:
[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;
Establecer las propiedades de los controles internos:
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;
Cargado:
procedure TNaharFMXPopup.Loaded;
begin
inherited;
ApplyControlsProp;
SetEvents;
end;
He intentado lo siguiente con la notificación, tratando de hacer que el control insertado sea padre para mi "clientarea" intencional
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;
Pero eso no hizo cambiar nada.
He hecho una pregunta similar anteriormente, pero no estaba al tanto de muchas cosas sobre la creación de dicho componente y la respuesta que recibí fue de poca ayuda, me faltaba el elemento principal de cada componente interno.
Ahora estoy tratando de mostrar realmente dónde está mi necesidad: necesito dejar los controles en mi diálogo de TPopup que se vinculará con el ClientArea dentro de él.
Creo que necesita un mediador en la creación de su control en un momento de diseño como este: http://sourcemaking.com/design_patterns/mediator/delphi
Eche un vistazo más de cerca a TTabControl / TTabItem en la unidad FMX.TabControl. Este es tu ejemplo perfecto porque básicamente necesita resolver el mismo problema.
La siguiente función es lo que necesita anular:
procedure DoAddObject(const AObject: TFmxObject); override;
Esto se llama cuando se agrega un control a su control. Anule esta función para que su control se agregue al control FpnlClientArea. Obtendrás algo similar a esto:
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;
Asegúrese de que AObject.Equals
también excluya sus otros controles "no almacenados".
Sin la anulación de DoAddObject, FMX TabControl mostraría el mismo problema que tiene actualmente su componente.
El TPopup no está destinado a aceptar controles. Entonces eso necesita algunos trucos más. Aquí hay una versión modificada de tu unidad que funciona para mí. He agregado algunos comentarios:
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.