Как создать диалоговое окно, подобное компоненту, которое позволяет добавлять другие элементы управления внутри него

43

Это компонент Firemonkey, однако я мог видеть, что большая часть базы компонентов одинакова для VCL и FMX, поэтому, пожалуйста, если вы знаете, как сделать это в VCL, поделиться своими знаниями, это может быть в конечном итоге решение для моего случай.

Я использую TPopup в качестве предка. Это удобно для меня, так как оно остается на форме/кадре, и я могу подключить его с помощью LiveBindings, используя тот же контекст/структуру родителя, что очень удобно для меня.

Мне нужно, чтобы он вел себя точно, это TPopup, как контейнер. Но мне нужно, чтобы он выглядел лучше, и у меня были определенные кнопки (я создал некоторые свойства и возможности для своего программного обеспечения внутри него)

Проблема заключается в том, что я создаю некоторые внутренние элементы управления, такие как TLayouts, Tpanels и Tbuttons, чтобы они выглядели следующим образом: (empty)

Изображение 680

В этой черной области внутри я хочу сбросить элементы управления, такие как TEdit и другие.

Я установил все внутренние созданные элементы управления Store = false, поэтому он не сохраняется в потоковой системе. Если это сделать, когда я бросаю TEdit, например, я получаю это (Tedit with aligned = top Мне это нужно):

Изображение 681

Однако я ожидал этого:

Изображение 682

Если я изменяю Store = true, я могу получить правильный эффект, но все внутренние элементы управления отображаются на панели "Структура", и каждый раз, когда я сохраняю форму и снова открываю, все дублируется. Внутренние компоненты, подверженные воздействию, для меня не проблема, но дублирование заключается в том, что если я закрою и открою компонент 10 раз, я получу всю внутреннюю структуру, реплицированную 10 раз.

Я попытаюсь показать код, связанный с конструкцией компонента:

Объявление класса:

  [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;

Настройка свойств внутренних элементов управления:

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;

Я попробовал следующее с уведомлением, пытаясь сделать вставленный элемент управления родительским для моей 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;

Но это ничего не изменило.

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

Теперь я пытаюсь показать, где моя потребность: мне нужно отключить элементы управления в моем диалоговом окне TPopup, который будет основан на ClientArea внутри него.

  • 7
    Для downvoter: почему это? Я приложил большие усилия для создания этого компонента, исследования и не знаю, что делать, чтобы это исправить. Я выставил лучше, чем мог, по этому вопросу. Пожалуйста, что я могу улучшить?
  • 5
    Fwiw, я думал, что -1 было немного странно, учитывая, что вы, очевидно, приложили немало усилий, чтобы приложить свои q вместе. Возможно, они сделают хедз-ап и объяснят.
Показать ещё 13 комментариев
Теги:
components
firemonkey
delphi-xe6

2 ответа

7
Лучший ответ

Познакомьтесь с TTabControl/TTabItem в блоке FMX.TabControl. Это ваш идеальный пример, потому что он в основном нуждается в решении одной и той же проблемы.

Следующая функция - это то, что вам нужно переопределить:

procedure DoAddObject(const AObject: TFmxObject); override;

Это вызывается, когда элемент управления добавляется в ваш элемент управления. Переопределите эту функцию, чтобы вместо этого элемент управления был добавлен в элемент управления FpnlClientArea. Вы получите что-то похожее на это:

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;

Убедитесь, что AObject.Equals также исключает ваши другие "не сохраненные" элементы управления.

Без переопределения DoAddObject, FMX TabControl будет показывать ту же проблему, что и ваш компонент.


TPopup не предназначен для приема элементов управления. Это требует еще нескольких трюков. Здесь измененная версия вашего подразделения, которая работает для меня. Я добавил несколько комментариев:

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.
  • 0
    Я вижу, что это имеет смысл, я сделал этот тест, добавил все AObject, Equals, чтобы исключить внутренние созданные элементы управления. Однако это не работает. Например, при добавлении TRectangle он не становится потомком My Component. Если я перетаскиваю его на Структурную панель, чтобы перетащить на этот компонент, он, кажется, добавляется как родительский, но не меняет свой корень и исчезает. из формы. Любая идея?
  • 0
    Можете ли вы опубликовать ссылку на полностью компилируемый источник, чтобы я мог попробовать это здесь?
Показать ещё 5 комментариев
-2

Я думаю, вам нужен медиатор в создании вашего контроля во время разработки следующим образом: http://sourcemaking.com/design_patterns/mediator/delphi

Ещё вопросы

Сообщество Overcoder
Наверх
Меню