(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;
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;
とするといいようです。
すみません、質問を読み違っていました。以下のようにします。
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;
とするといいようです。
なんどもすみません。
うえの回答を撤回します。
この質問の難しさがだんだん分かってきました。上の回答では 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 の変更はありません。
つっかさん、返事遅くなりまして申し訳ありません。
すばやく、また丁寧なご回答ありがとうございます。
結論を申しますと、上記のようなソースを組んだアプリケーションですと、前画面に戻る動作はうまくいきました。感謝します。しかし、更に、前の画面に戻ろうとすると「モジュール'test.exe'のアドレス00403471でアドレス00000002に対する読み込み違反がおきました。」というメッセージが出て強制終了以外受け付けない状態に陥ってしまいます。
よって、せっかく考えて下さったのですが、Form2をクローズするときに、Form3をReleaseし、Form3をクローズするときに、Form2をReleaseするようにしました。変更後は、問題なく稼動していますので、ありがとうございました。
> 強制終了以外受け付けない状態に陥ってしまいます。
そうですか? そんなことはありませんけど?
Close Hide Release の意味が分かれば、一方を Release し、他方を Close
するのは、完全に間違っていますよ。
> 更に、前の画面に戻ろうとすると
これは OnClose で Action := caFree; してしまったり、Release してしまった
インスタンスにアクセスしようとするからでは? つっかさんの最後の回答では
Form2 と Form3 はどちらも非表示になるだけですので、エラーにはなりませんね。
> Close Hide Release の意味が分かれば
これは、最初のうち、けっこうはまりますね。デフォルトの MainForm である
Form1 とそれ以外のフォームでは Close の動作が違うので。
あと、OnClose で Action := caFree; してるかどうかも、かなり重要です。
ツイート | ![]() |