複数画面を同時に閉じた後に、特定の画面を表示するには?

解決


kuriox  2004-04-16 22:15:50  No: 8410

(1)Form1上にButtonを配置し、そのButtonをクリックすると、Form1が閉じ、Form2とForm3が表示される。
(2)Form2,Form3どちらかを閉じようとすると、両Formとも閉じ、Form1が表示される。
といったものを作りたいと思っています。
(1)はうまくいったのですが、(2)を実行しようとするとForm2,Form3は閉じるのですが、Form1を表示させることが出来ません。
以下にソースの一部を記載しますので、ご教授お願いいたします。

【参考】
Form1:
procedure TForm1.btNextClick(Sender: TObject);
begin
 Form2 := TForm2.Create(Application);
 Form2.Show;
 Form3 := TForm3.Create(Application);
 Form3.Show;
 Self.Hide;
end;

Form2:
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 AllClose;
end;

procedure TForm2.AllClose;
var
 Form2_Flg,Form3_Flg : Boolean;
begin
 Form2_Flg := True;
 Form3_Flg := True;
 try
  Form2.Close;
 except
  Form2_Flg := False;
 end;
 if Form2_Flg then
  Form2.Close;
 try
  Form3.Close;
 except
  Form3_Flg := False;
 end;
 if Form3_Flg then
  Form3.Close;
 Form1.Show;
end;

Form3:
procedure Form3.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 Form2.AllClose;
end;


つっか  2004-04-16 23:21:16  No: 8411

AllClose を TForm1 のメソッドにして

    { Private 宣言 }
  public
    procedure AllClose;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

uses
  Unit2,Unit3;

procedure TForm1.AllClose;
var
  i:integer;
begin
  for i := 0 to Screen.CustomFormCount-1 do
    if Screen.CustomForms[i] is TForm1 then
      Screen.CustomForms[i].Show
    else
      Screen.CustomForms[i].Release;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Form2 := TForm2.Create(Application);
  Form2.Show;
  Form3 := TForm3.Create(Application);
  Form3.Show;
  Self.Hide;
end;

そして Unit2.pas では

uses
  Unit1;

procedure TForm2.Button1Click(Sender: TObject);
begin
  Form1.AllClose;
end;

Unit3.pas でも

uses
  Unit1;

procedure TForm3.Button1Click(Sender: TObject);
begin
  Form1.AllClose;
end;

とするといいようです。


つっか  2004-04-16 23:30:17  No: 8412

すみません、質問を読み違っていました。以下のようにします。

AllClose を TForm1 のメソッドにして

    { Private 宣言 }
  public
    procedure AllClose(Sender:TForm);
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

uses
  Unit2,Unit3;

procedure TForm1.AllClose(Sender:TForm);
var
  i:integer;
begin
  for i := 0 to Screen.CustomFormCount-1 do
    if Screen.CustomForms[i] is TForm1 then
      Screen.CustomForms[i].Show
    else if not (Screen.CustomForms[i] = Sender) then
      Screen.CustomForms[i].Release;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Form2 := TForm2.Create(Application);
  Form2.Show;
  Form3 := TForm3.Create(Application);
  Form3.Show;
  Self.Hide;
end;

そして Unit2.pas では

uses
  Unit1;

procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Form1.AllClose(Self);
end;

Unit3.pas でも

uses
  Unit1;

procedure TForm3.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Form1.AllClose(Self);
end;

とするといいようです。


つっか  2004-04-17 00:38:02  No: 8413

なんどもすみません。

うえの回答を撤回します。
この質問の難しさがだんだん分かってきました。上の回答では Release を
実行すると OnClose イベントが呼ばれないことを利用していますが、最初に
クロースしたフォームは、Free されないで残りますね。質問では、どちらも
Free しないで Close だけを行いたいようですから、上の回答は不十分です。

Release ではなく Hide メソッドでも OnClose イベントが呼ばれませんね。

Unit1.pas の部分だけ、以下のように訂正します。

procedure TForm1.AllClose(Sender:TForm);
var
  i:integer;
begin
  for i := 0 to Screen.CustomFormCount-1 do
    if Screen.CustomForms[i] is TForm1 then
      Screen.CustomForms[i].Show
    else if not (Screen.CustomForms[i] = Sender) then
      Screen.CustomForms[i].Hide;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  if not Assigned(Form2) then Form2 := TForm2.Create(Application);
  Form2.Show;
  if not Assigned(Form3) then Form3 := TForm3.Create(Application);
  Form3.Show;
  Self.Hide;
end;

Unit2.pas と Unit3.pas の変更はありません。


kuriox  2004-04-17 02:55:40  No: 8414

つっかさん、返事遅くなりまして申し訳ありません。
すばやく、また丁寧なご回答ありがとうございます。
結論を申しますと、上記のようなソースを組んだアプリケーションですと、前画面に戻る動作はうまくいきました。感謝します。しかし、更に、前の画面に戻ろうとすると「モジュール'test.exe'のアドレス00403471でアドレス00000002に対する読み込み違反がおきました。」というメッセージが出て強制終了以外受け付けない状態に陥ってしまいます。
よって、せっかく考えて下さったのですが、Form2をクローズするときに、Form3をReleaseし、Form3をクローズするときに、Form2をReleaseするようにしました。変更後は、問題なく稼動していますので、ありがとうございました。


つっか  2004-04-17 06:52:43  No: 8415

> 強制終了以外受け付けない状態に陥ってしまいます。

そうですか? そんなことはありませんけど?

Close Hide Release の意味が分かれば、一方を Release し、他方を Close
するのは、完全に間違っていますよ。


jok  2004-04-17 08:06:23  No: 8416

> 更に、前の画面に戻ろうとすると

これは OnClose で Action := caFree; してしまったり、Release してしまった
インスタンスにアクセスしようとするからでは? つっかさんの最後の回答では
Form2 と Form3 はどちらも非表示になるだけですので、エラーにはなりませんね。

> Close Hide Release の意味が分かれば

これは、最初のうち、けっこうはまりますね。デフォルトの MainForm である
Form1 とそれ以外のフォームでは Close の動作が違うので。
あと、OnClose で Action := caFree; してるかどうかも、かなり重要です。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加