Migaro. 技術Tips

                       

ミガロ. 製品の技術情報
IBMiの活用に役立つ情報を掲載!


【Delphi】フォームの呼び出され方を判断

今回はDelphi/400で呼び出されたフォーム側で、
モーダルの状態を判断するテクニックをご紹介いたします。

Delphi/400では複数画面のアプリケーションを作成する場合、
標準的なフォームの呼び出し方法ではShowまたはShowModalのメソッドを使います。

この2つの違いは次の通りです。
①Show   :モードレスなフォームの表示
②ShowModal:モーダルなフォームの表示

①の場合、呼び出し先フォームを開いた後も、呼び出し元フォームと切替ができますが、
②では呼び出し元フォームに切り替えることはできません。
その代わり、②では次のフォームを閉じるまで呼び出し元フォームで処理を待つことができます。

また呼び出し先フォームの解放についても、手法に違いがあります。
①では、呼び出されたフォーム自身で破棄を行います。

// 例)呼び出し先フォームのCloseイベント
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree; // クローズ時に破棄
end;

②では、呼び出し先フォームを閉じた後に、
呼び出し元フォームで破棄します。

// 例)呼び出し元フォームの呼出イベント
procedure TForm1.Button1Click(Sender: TObject);
begin
  Form2 := TForm2.Create(Application);
  try
    if (Form2.ShowModal = mrOK) then  //【※1】(下記参照)
    begin
      ShowMessage('Form2をOKで閉じました。');
    end;
  finally
    Form2.Free; // 破棄
  end
end;

//【※1】呼び出し先からの結果をデバッグで確認したい場合、以下のように分けることも可能
    Form2.ShowModal;
    if (Form2.ModalResult = mrOK) then
    begin
      ShowMessage('Form2をOKで閉じました。');
    end;

 
また②の場合、呼び出し先フォームでModalResultプロパティが設定されると、
処理終了時にそのModalResultを持って画面が閉じられます。
(ModalResultを設定せずにただフォームを閉じた場合、mrCancelが返されます。)
①の場合はModalResultプロパティを設定しても何も起こりません。

// 例)呼び出し先でOKボタン押下時
procedure TForm1.ButtonOKClick(Sender: TObject);
begin
  // Closeはモーダルの場合は必須ではないが、
  // 明示的に書く場合はModalResult設定より先に行う(Closeは内部的にmrCancelがセットされる)
  Self.Close;
  // mrNone以外の結果をセットするだけで、モーダルなら処理後に閉じられる
  Self.ModalResult := mrOk;
end;

 

このように呼び出され方によって扱いも異なりますので、
呼び出し先フォーム側でこれを考慮する場合には、モーダル状態の把握が必要になります。
モーダル状態はフォームのFormStateプロパティで次のように判断できます。

例)ShowModalで呼び出されたかを判断
  if fsmodal in Form2.FormState then
  begin
    ShowMessage('ShowModalで開かれています');
  end;

 
最初にロジックを例示した呼び出し先フォームのCloseイベントも、
ShowModalで開いていた場合はクローズ時に解放してしまうと
呼び出し元画面で結果を参照できずエラーになるため、
①Show・②ShowModal の呼び分けが必要な場合は以下のような条件分岐が必要です。
太字下線の部分を追加)

// 例)呼び出し先フォームのCloseイベント【修正版】
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  if not(fsmodal in Form2.FormState) then // モーダル状態でない場合のみ
  begin
    Action := caFree; // クローズ時に破棄
  end;
end;

汎用的な共通画面などを作る場合に有効なテクニックですので、
呼び出し元の処理を考慮してご活用ください。


 

(ミガロ.情報マガジン「MIGARO News!!」Vol.198 2017年5月号より)