モーダルなフォーム

例えば、フォームが2つある場合(ここではメインフォーム( Form1 )、サブフォーム( Form2 )の2つとします。)、サブフォームをモーダルかモードレスに設定することが出来ます。 モーダルにした場合、その表示されたフォームが閉じられない限り別のフォームをアクティブにすることは出来なくなります。これは、ダイアログボックスなどで、よく使われます。

実際にモーダルなフォームがどんなものなのかを試して見ましょう。まず、Delphi を起動した直後の状態では、Form1 があるだけですので、新しくフォームを追加します。「ファイル」→「新規作成」→「フォーム」でフォームを追加してください。すると、Form2 が表示されると思います。(エディタの方にも Unit2 が追加されます)次に、Form1 にボタンを貼り付けて以下のコードを書いてください。

procedure TForm1.Button1Click(Sender: TObject);
begin
  Form2.ShowModal; // モーダルで表示
end;     

この状態でコンパイルしますと、「未定義の識別子Form2」と出て Unit2 を追加しますかと聞かれますので、そこで「はい」を選択して下さい。すると、Delphi が自動的に以下のように uses 節を追加してくれます。

var
  Form1: TForm1;
 
implementation
  
uses Unit2; // 追加してくれます。
  
{$R *.dfm}
  
procedure TForm1.Button1Click(Sender: TObject);
begin
  Form2.ShowModal;
end;

このように、他のユニット(ここでは Unit2 )を参照する場合には、uses 節に「使いますよ」と宣言しなければなりません。しかし、それを忘れたとしてもコンパイル時に Delphi が教えてくれるので、あまり気にする必要は無いと思います。

それでは、実行してみてください。Form1 のボタンを押すと Form2 が表示されるはずです。Form2 はモーダルとして設定しましたので Form2 を閉じない限り Form1 をアクティブにすることは出来なくなっています。今の段階では、Form2 を閉じる方法は Form2 の右上にあるバツボタンで閉じるしか方法がありません。実際、フォームをモーダルにする理由は、そこで何らかの値などを設定して、それを別のフォームに渡す時などに使われるはずですので、バツボタン以外でフォームを閉じる方法が必要です。動作としては、フォームを閉じ、且つ、そのモーダルフォームで設定した値などを渡す動作をしてくれなければなりません。 そこで、役立つのが ModalResult プロパティです。このプロパティはフォームではなくボタンに存在するプロパティです。この ModalResult プロパティに適切な値を設定してやると、モーダルフォームは閉じることが出来ます。

それでは、今度は Form2 にボタンを一つ貼り付けて下さい。そして、そのボタンの ModalResult プロパティを mrOK にして下さい。このようにすればボタンを押すだけで、モーダルフォームである Form2 は閉じることが出来ます。試しに実行して、本当に閉じられるか確認してみてください。

さて、ここまでで適切にモーダルフォームを閉じることが出来ましたが、ただ単に閉じられるだけで、まだ何の役にも立っていません。今度は Unit1 ( Form1 )の方で、何か値を受け取るように設定してみましょう。

では、さらに Form2 に Edit を一つ貼り付けて下さい。そして Form1 の方にはラベルを貼り付けて下さい。出来ましたら Unit1 ( Form1 )の方に以下のコードを書きます。

procedure TForm1.Button1Click(Sender: TObject);
begin
  if Form2.ShowModal = mrOK then
    Label1.Caption := Form2.Edit1.Text;
end;

このように、if 文でモーダルフォームが閉じられる時に ShowModal メソッドから返される値(ここでは mrOK )を設定してやれば、うまい具合に Form1 の方に値を渡すことが出来ます。もちろん ModalResult プロパティには mrOK 以外にも沢山の値があるので、状況に応じて様々な動作をさせることも出来ます。

何故ボタンを押すとモーダルフォームを閉じることが出来たのか
理由は、上にも書いたように、ずばり ModalResult プロパティに値を設定したからです。具体的に言いますと、 ModalResult プロパティが0以外( mrNone が値として0です)の値が代入されると、モーダルフォームが閉じられます。結果として、ShowModal メソッドが ModalResult プロパティに代入された値を戻り値として返してもらっていることになります。そう考えると上記の if 文も理解できるのではないでしょうか。

また、ModalResult が0以外の値を代入すればモーダルフォームが閉じられるので以下のように書いてもモーダルフォームは閉じられます。

procedure TForm2.Button1Click(Sender: TObject);
begin
  ModalResult := 1000;
end;        

ただ、これだと何を意味しているのかが分からないので、具体的な数字ではなく mrOK や mrCancel 等に設定しているのだと思います。

これで、モーダルフォームについては理解できたと思います。それでは今度は、このモーダルフォームを動的に作成してみましょう。

上の例では、新しくフォームを追加するのに「ファイル」→「新規作成」→「フォーム」と選択してフォームを追加したのでした。この場合、追加したフォームは、自動的に Delphi が管理してくれています。つまり Delphi が、このフォーム( Form2 )をプログラム実行時に生成して、終了時に破棄してくれているのです。これは、「プロジェクト」→「オプション」で確認できます。

このように、「自動作成の対象」に Form2 が追加されています。
では、このフォーム( Form2 )を動的に作成するようにして見ましょう。
それには、上の図で Form2 を選択して「>」ボタンを押してください。すると、Form2 が「選択可能なフォーム」に移動するはずです。このようにフォームを動的に作成する場合には、その動的に作成するフォームを必ず「選択可能なフォーム」に設定することを忘れないで下さい。とても大事です。

これで、From2 は動的に作成することが出来ます。動的に作成する場合、注意しなければならないのはプログラマが責任を持って、生成と破棄をしなければなりません。コードは以下のようになります。

procedure TForm1.Button1Click(Sender: TObject);
begin
  Form2 := TForm2.Create(Application); // 生成
  try
    if Form2.ShowModal = mrOK then
      Label1.Caption := Form2.Edit1.Text;
  finally
    Form2.Free; // 破棄
  end;
end;

これで、フォーム( Form2 )が必要な時だけ生成され、いらなくなったら破棄することが出来ました。このように、モーダルなフォームの場合は動的に作成することは比較的容易に出来ます。しかし、モードレス(非モーダル)なフォームの場合は、少し注意が必要になってきます。これは次回、みていきたいと思います。


up next
Last update: 2002/5/12