Поддельный модальный диалог с помощью Show?

Мое приложение имеет несколько модулей, каждый на одной вкладке в основной форме. При использовании диалога удобно вызывать ShowModal, потому что вы знаете, когда диалог закончен. Но для пользователя это нехорошо, поскольку блокирует всю программу до закрытия диалога.

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

Я должен сделать для этого какую-то основу, которую могут использовать все диалоги в приложении. У меня есть базовый класс для всех диалогов TAttracsForm, и я думаю, что именно здесь можно добавить мой метод Show().

Это должно заблокировать доступ ко всем wincontrols только в текущем модуле. Он должен имитировать вызов ShowModal(). Как мне этого добиться?

С уважением

3 ответа

Решение

Я фактически почти реализовал локальные модальные диалоги. Он построен на том, что когда свойство TForms Enabled установлено в значение False, вся форма блокируется от ввода. А мои модули просто потомок от TForm.

Мой класс ViewManager, который решает, какие модули являются текущими модулями добавления / закрытия и т. Д., Получил 2 новых метода. LockCurrentView и UnLOckCurrentView.

function TViewManager.LockCurrentView: TChildTemplate;
begin
  Result := CurrentView;
  Result.Enabled := False;
  Result.VMDeactivate;         // DeActivate menus and toolbas for this module
end;

procedure TViewManager.UnLockCurrentView(aCallerForm: TChildTemplate);
begin
  aCallerForm.VMActivate;           // Activate menus and toolbas for this module
  aCallerForm.Enabled := True;
end;

TAttracsForm является базовым классом всех диалогов. Я переопределяю FormClose и добавляю новый метод ShowLocalModal для вызова вместо ShowModal. Я также должен добавить TNotifyEvent OnAfterDestruction, который будет вызываться при закрытии диалога.

procedure TAttracsForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  if Assigned(fCallerForm) then      
  begin
    ClientMainForm.ViewManager.UnLockCurrentView(fCallerForm as TChildTemplate);

    if Assigned(OnAfterDestruction) then
      OnAfterDestruction(Self);

    Action := caFree;
  end;
end;

{ Call to make a dialog modal per module.
  Limitation is that the creator of the module must be a TChildtemplate.
  Several modal dialogs cannot be stacked with this method.}
procedure TAttracsForm.ShowLocalModal(aNotifyAfterClose: TNotifyEvent);
begin
  fCallerForm := ClientMainForm.ViewManager.LockCurrentView;    // Lock current module and return it
  PopupParent := fCallerForm;
  OnAfterDestruction := aNotifyAfterClose;
  Show;
end;

Некоторый тест с простыми диалогами выглядит многообещающим. Таким образом, модуль просто должен вызвать ShowLocalModal(myMethod), который имеет TNotifyEvent в качестве параметра. Этот метод вызывается, когда диалог закрыт.

Вам нужно будет сделать следующее:

  1. Иметь личность для каждого модуля
  2. Иметь флаг, который является активным или неактивным для каждого модуля
  3. Имейте флаг, который хранит модальность присоединенного диалога. Если он модальный и модуль активен, вызовите метод show в соответствующем обработчике событий. Не забудьте обновить эти значения в событиях onshow и onclose каждого диалога.

Возможно, вам придется настроить это предложение, пока вы не достигнете именно той функциональности, которая вам требуется.

Вы все еще хотите реализовать это с метафорой "вы знаете, когда диалог закончен"? Так нравится

DoSomethingBeforeDialog(); 
Form:=TFakeFormDialog.Create(Nil);
try
   Form.FakeShowModal();
finally
  Form.Free;
end;
DoSomethingAfterDialog();  

если ответ "да", вы можете попытаться реализовать это с помощью потоков, как в Google Chrome - с помощью вкладок. Но без потоков только вы можете поймать обработку сообщений с помощью кода, подобного этому

function TFakeModalDlg.FakeShowModal(FormParent: TWinControl): boolean;
begin
  Parent:=FormParent;
  SetBounds((FormParent.Width - Width) div 2, (FormParent.Height - Height) div 2,
    Width, Height);
  Show;
  while NoButtonIsPressed() do
  begin
    Application.HandleMessage;
  end;
  Hide;
end;

И у вас даже есть код ниже...

Form:=TFakeModalDlg.Create(Nil);
try
  (Sender as TButton).Caption:='Going modal...';
  Form.FakeShowModal(TabSheet1);
  (Sender as TButton).Caption:='Returned from modal';
finally
  Form.Free;
end;

вызывается несколько раз из ваших вкладок, но проблема в том, что эти "диалоги" должны быть закрыты в "порядке стека", т.е. в обратном порядке, в котором они были показаны. Я думаю, что невозможно заставить пользователей закрывать формы в порядке предпочтения разработчиков:)

Другие вопросы по тегам