使用Show的假模态对话框?

时间:2009-08-19 11:35:01

标签: delphi user-interface modal-dialog

我的应用程序有几个模块,每个模块位于主窗体的一个选项卡中。 使用对话框时,可以方便地调用ShowModal,因为您知道对话框何时完成。但对于用户而言,在对话框关闭之前锁定整个程序并不好。

我想要一个本地模态对话框。因此,一个模块可以打开一个对话框,它只锁定当前模块。用户仍然可以切换到另一个模块并继续工作。如果用户返回到第一个模块,则对话框在那里等待关闭,然后用户才能继续在该模块中工作。

我必须为此创建某种框架,以便应用程序中的所有对话框都可以使用。 我有一个基类用于所有对话框TAttracsForm,我想这里是添加我的Show()方法的地方。

这应该只锁定当前模块中对所有wincontrols的访问。 它应该模拟对ShowModal()的调用。我怎样才能做到这一点?

此致

3 个答案:

答案 0 :(得分:2)

您必须执行以下操作:

  1. 拥有每个模块的身份
  2. 为每个模块设置一个活动或非活动的标志
  3. 有一个标志,用于存储附加对话框的模态。如果它是模态的并且模块处于活动状态,则在相应的事件处理程序中调用show方法。请记住在每个对话框的onshow和onclose事件中更新这些值。
  4. 您可能需要对此建议进行微调,直到您获得所需的确切功能。

答案 1 :(得分:2)

你还想用“你知道什么时候对话完成”比喻来实现这个吗? 所以喜欢

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;

从选项卡中调用乘法时间,但问题是这些“对话框”应该以“堆栈顺序”关闭,即与它们显示的顺序相反。我认为强制用户在开发者偏好顺序中关闭表单是不可能的。

答案 2 :(得分:1)

我现在几乎实现了本地模态对话框。 它是建立在当TForms Enabled属性设置为False时,整个表单从输入锁定。我的模块只是TForm的后代。

我的ViewManager类决定了哪些模块是当前的添加/关闭模块等,它有两种新方法。 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作为参数。关闭对话框时会调用此方法。