从外部关闭模态形式并打开新的模态形式

时间:2016-11-16 11:25:08

标签: delphi

在我的主要表单中,我有一个按钮,可以打开一个模态Form2(可以打开其他模态表单)。在打开Form2之前我正在设置一个计时器,它将以编程方式关闭所有活动的模态表单(Form2.Close)并打开一个新的模态Form3

问题是当Form3以模态方式打开时,Form2保持(可见),并且仅当我通过点击Form3X关闭Form2时关闭TButton

要重现向项目添加3个表单,请添加TTimer,并在Form1(主表单)上删除unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls; type TForm1 = class(TForm) Button1: TButton; Timer1: TTimer; procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure Timer1Timer(Sender: TObject); private public end; var Form1: TForm1; implementation uses Unit2, Unit3; {$R *.DFM} procedure TForm1.FormCreate(Sender: TObject); begin Timer1.Enabled := False; end; procedure TForm1.Button1Click(Sender: TObject); begin Timer1.Enabled := True; with TForm2.Create(Application) do try ShowModal; finally Free; end; end; procedure CloseActiveModalForms; var I: Integer; F: TCustomForm; L: TList; // list of modal forms begin L := TList.Create; try for I := 0 to Screen.CustomFormCount - 1 do begin F := Screen.CustomForms[I]; if (fsModal in F.FormState) then L.Add(F); end; for I := 0 to L.Count - 1 do TCustomForm(L.Items[I]).Close; // this sets ModalResult := mrCancel finally L.Free; end; end; procedure TForm1.Timer1Timer(Sender: TObject); begin Timer1.Enabled := False; CloseActiveModalForms; // this should close TForm2 but it does not. with TForm3.Create(Application) do // create new Modal TForm3 try ShowModal; finally Free; end; end; end.

Form2

为什么Form2没有关闭?调用CloseActiveModalForms后,为什么D: $dcmtk: dsrdump v3.6.1 DEV $ D: [...] W: Date (0040,a121) empty in content item (type 1) W: Reading invalid/incomplete content item DATE "1.3.1" E: Reading content item DATE "1.3.1" (Invalid Value) D: ------------------------------- DICOM DATA SET ------------------------------- D: (fffe,e000) na (Item with explicit length #=4) # 98, 1 Item D: (0040,a010) CS [CONTAINS] # 8, 1 RelationshipType D: (0040,a040) CS [DATE] # 4, 1 ValueType D: (0040,a043) SQ (Sequence with explicit length #=1) # 54, 1 ConceptNameCodeSequence D: (fffe,e000) na (Item with explicit length #=3) # 46, 1 Item D: (0008,0100) SH [11779-6] # 8, 1 CodeValue D: (0008,0102) SH [LN] # 2, 1 CodingSchemeDesignator D: (0008,0104) LO [EDD from LMP] # 12, 1 CodeMeaning D: (fffe,e00d) na (ItemDelimitationItem for re-encoding) # 0, 0 ItemDelimitationItem D: (fffe,e0dd) na (SequenceDelimitationItem for re-encod.) # 0, 0 SequenceDelimitationItem D: (0040,a121) DA (no value available) # 0, 0 Date D: (fffe,e00d) na (ItemDelimitationItem for re-encoding) # 0, 0 ItemDelimitationItem D: ------------------------------------------------------------------------------ E: Reading content item CONTAINER "1.3" (Invalid Value) 模态循环没有退出?

1 个答案:

答案 0 :(得分:5)

您的调用堆栈如下所示:

1 Form1.Button1Click
2 Form2.ShowModal //Local message processing loop until form closes
3 Form1.Timer1Timer //Here you attempt to close the form
                    //but it doesn't actually until ShowModal exits
4 Form3.ShowModal // Another message loop that doesn't return until form closes

基本上,在Form3关闭之前,你无法完成Form2的关闭。请注意,ShowModal阻止调用以显示表单。如果您只是Show Form3(即不是ShowModal),则调用不会阻止,并且您将看到Form2能够在调用堆栈展开时关闭。

你应该可以通过延迟调用show Form3直到Form2关闭之后来解决这个问题。 OnFormDestroyEvent应该足够了(遗憾的是我无法测试它)。

procedure TForm1.ShowForm3(Sender: TObject);
var
  LForm: TForm;
begin
  LForm := TForm3.Create(Application); //as you created it, but nil owner should suffice
  try
    LForm.ShowModal;
  finally
    LForm.Free;
  end; 
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Timer1.Enabled := False;
  //You will need to figure out how you reference the Form2 instance.
  Form2.OnFormDestroy := ShowForm3;
  CloseActiveModalForms;
  //Form2 will close after you backtrack up the call-stack.
  //When it's destroyed, your event handler will create and show a TForm3 instance.
end;

注意上面简单地说明了这个概念。根据您的最终目标,您需要设计一种更强大的方法。

但是,我建议过度使用模态表格通常被认为在用户体验方面不友好。