メインフォーム以外の不特定なフォームを閉じるには?

解決


  2005-01-15 04:17:47  No: 12716

メインフォームのタイマイベントにて、ある時間がきたら
メインフォーム以外の全てのウィンドウを閉じて、
実行中のモーダルフォームを表示させたいのですがうまくいきません。
よい方法はないでしょうか?

ちなみに以下の方法ではフォームが閉じずに実行中のモーダルフォームが
表示されます。
(メインフォーム、子フォームの親は全てApplication)

for i:=0 to Application.ComponentCount-1 do
begin
  if Application.Components[i] is TForm then
  begin
    if Application.Components[i] <> MainForm then
    begin
      Application.Components[i] as TForm).Close;
    end;
  end;
end;

JikkouchuuForm := TJikkouchuuForm.Create(Application);
JikkouchuuForm.ShowModal;
JikkouchuuForm.Free;


jok  2005-01-15 04:50:40  No: 12717

普通は Screen.FormCount と Screen.Forms を使いますけど


  2005-01-15 05:42:01  No: 12718

なるほど、Screen変数を使うと簡単にできるんですね。
勉強になります。

さて本題のフォームが閉じない現象はなぜなのでしょう?
ループで全部閉じた後、フォームを表示しているつもり
なのですが、閉じずに残ったまま、その上にフォームを
表示してしまいます。

ちなみに実行中のモーダルフォームを閉じるタイミングで
下に残っていたフォームも閉じます。

よろしくお願いします。


jok  2005-01-15 06:11:09  No: 12719

uses
  Unit2;

procedure TForm1.Button1Click(Sender: TObject);
begin
  with TForm2.Create(Application) do Show;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  i:integer;
begin
  for i := 0 to Screen.FormCount-1 do
    if Screen.Forms[i] <> Application.MainForm then
      Screen.Forms[i].Close;

  ShowMessage('ModalForm');
end;

こんなコードで Button1 を何回か押して Form2 を複数つくっておいてから
Button2 を押すとD6では期待通りになりますけど


  2005-01-17 03:33:47  No: 12720

ご回答ありがとうございます。
jokさんの回答どおりで確かに、メイン以外のフォームが消えて
別のモーダルフォームの表示ができました。
しかし、私がわからないのは、モーダルフォームをいくつか
開いておいて、ある時間(タイマイベント)がきたときに
メインフォーム以外のモーダルフォームを閉じて別のモーダルフォーム
を開くということです。
jokさんの回答に処理をあてはめてみましたが、あらかじめ表示していた
モーダルフォームが消えずにShowMessageが表示されました。
なぜなのでしょうか?
説明不足で申し訳ありませんでしたが、再度ご回答いただければ
ありがたく思います。


しょーとかっと  2005-01-18 08:15:09  No: 12721

>しかし、私がわからないのは、モーダルフォームをいくつか開いておいて、
一つ ShowModal したら、そこでプログラムが止まるのでは?
どのように複数のモーダルフォームを開いているのかなど、最低限のソースでも
示して質問しないと…


  2005-01-18 17:50:42  No: 12722

申し訳ありません。
以下に簡単なソースを示します。

// メインフォームボタンクリック
procedure TForm1.Button1Click(Sender: TObject);
begin
  with TForm2.Create(Application) do
  begin
    ShowModal;
    Free;
  end;
end;

// メインフォームタイマイベント(5sec間隔にプロパティ設定)
procedure TForm1.Timer1Timer(Sender: TObject);
var
  i: Integer;
begin
  for i:=0 to Screen.FormCount-1 do
  begin
    if Screen.Forms[i] <> Application.MainForm then
    begin
      Screen.Forms[i].Close;
    end;
  end;
  with TForm3.Create(Application) do
  begin
    ShowModal;
    Free;
  end;
  Timer1.Enabled := False;
end;

Button1クリックでForm2を開いておいて、5sec後のタイマイベントにて
Form2を閉じてForm3を表示したい、といった感じです。

しかし、上記ソースでは5sec後のタイマイベントにてForm2を閉じることなく
Form2の上にForm3が開き、Form3を閉じた時にForm2が一緒に閉じられます。

仮にForm2をモードレスフォームとして開いた場合は問題なく動作します。
モーダルフォームの場合はまずいのでしょうか?

よろしくお願いします。


  2005-01-18 18:38:37  No: 12723

Timer1のEnabledの使い方が間違っています。
[ヒント]
  ダミーでいいので Timer1関数の最初にif i=0 then ; をかいて
  ブレークポイントを関数の最初においてみましょう。

もう一つ  
Screen.Forms[i].Close;

Screen.Forms[i].Hide;
Screen.Forms[i].Close;

にするか
本気で消すきがあるのなら、

  with TForm2.Create(Application) do
  begin
    ShowModal;
    Free;
  end;
からFreeを排除して
  with TForm2.Create(Application) do
  begin
    ShowModal;
  end;
にして、

  for i:=Screen.FormCount-1 downto 0 do
  begin
    if Screen.Forms[i] <> Application.MainForm then
    begin
      Screen.Forms[i].Free;
    end;
にかえればいいこと

以上。


  2005-01-18 18:48:21  No: 12724

// メインフォームタイマイベント(5sec間隔にプロパティ設定)
イベントがあったときにonにして5sec間隔でタイマー稼働させたいのか
5sec後に実行して止めるのかはっきりかきましょう。

それによって
コードが大きく変わります。

Screen.Forms[i].Hide;
Screen.Forms[i].Close;
の方向でいったらどうでしょ


kkk  2005-01-18 19:21:57  No: 12725

1回のタイマーイベント中で、Closeと次のフォーム(TForm3)のShowModalを行うとだめみたいですね。
複数のイベントで別々に処理すればOKです。
最初のイベントでCloseだけを行い次のイベントでShowModalを行うというように。


kkk  2005-01-18 19:34:44  No: 12726

ようは1回のメッセージループでは処理できないということ。
タイマ1のイベントの中でWM_USER+???等のメッセージを投げて処理するか、
テスト的に簡単に行うならタイマ2を用意してインターバルを1に設定する。
タイマ1のイベント中でCloseを行いタイマ2を起動する。
タイマ2の中でShowModalを行う・・・


  2005-01-18 20:03:53  No: 12727

jok様、しょーとかっと様、。様、kkk様、ありがとうござます。

。様の
>Screen.Forms[i].Hide;
>Screen.Forms[i].Close;

の方向で進めていこうと思います。

タイマイベントについてサンプルでは、アプリ起動後5秒後にイベントが
発生して、Button1にて開いたForm2を消して、Form3を開くといった単純な
ものを書いたつもりでしたが、確かにEnabledが変でまぎらわしかったですね。
申し訳ありません。

kkk様のおっしゃるとおり、1回のタイマイベント中でCloseと次のフォームの
ShowModalはだめみたいですね。ただ、Closeするフォームがモードレスならば
問題なく消えたので、その点がよくわからないです。
見た目だけの問題なのであまり複雑にしたくなかったので。様の方法を選択しま
した。

ありがとうございました。


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

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






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