モーダルダイアログとモードレスダイアログ

今まで作ってきたダイアログは、すべてモーダルダイアログと呼ばれるものでした。 今回はモードレスダイアログを作ります。この二つの違いは何でしょうか?

ユーザーの立場では、モーダルダイアログとは、そのダイアログを閉じない限り メインウィンドウの操作ができないものを言います。そしてたいていは「OK」と「キャンセル」 のボタンを持ち、どちらを押してもダイアログが閉じます。たとえばメッセージボ ックスやファイルオープンのダイアログなどが該当します。一方、モードレスダイアログ とは、そのダイアログを閉じなくても、メインウィンドウ側を操作することができ るものです。そして「OK」ではダイアログは閉じない作りになっていることが多い です。また、「キャンセル」は「終了」とか「閉じる」という表示になっていることも多くあります。 たとえばメモ帳を起動して、「検索」ダイアログを出し てみてください。このダイアログを閉じなくても、メモ帳のメインウインドウに戻 って、スクロールや文字の入力ができるはずです。

一方、プログラマの立場では、「親を無効にしたモードレスダイアログで、モーダル ダイアログをシミュレートする」などといった言い方をすることがあります。 つまりここでいうモーダルとモードレスの違いは、ユーザーインターフェースの 違いではなく、実現方法の違いなわけです。

具体的に言うと、DialogBox() APIで作成するのがモーダルダイアログで、 CreateDialog() APIで作成するのがモードレスダイアログです。ではこれらの 実現方法の違いは、プログラムの作り方や挙動にどうかかわってくるのでしょう か? 親ウィンドウが存在するときは、その挙動ははっきり違います。DialogBox APIで作ったダイアログでは、親を有効にできません。では、それ以上親が存在 しない時は?

実際、今までの「ダイアログをメインウィンドウにしたアプリ」では、そのメイン のダイアログにはそれ以上「親」と呼べるウィンドウがないので、モーダルでも モードレスでも同じはずです。しかし、微妙に違いはあります。

ソース上の違い

CreateDialog APIは、DialogBox APIと違い、ダイアログボックスを 作成したらただちに戻ってきます。よって、そのあと、ダイアログが閉じるまで 待ちつづけなければなりません。WinMain()は、以下のようになります。
int PASCAL WinMain(HINSTANCE hinst, HINSTANCE hprev, LPSTR cmdline, int cmdshow){
	DLGPROC lpProc = (DLGPROC)MakeProcInstance((FARPROC)easyplay, hinst);
	HWND hDlg=CreateDialog(hinst, "EASYPLAY", NULL, lpProc);/*ダイアログ作成*/
	MSG msg;
	while (GetMessage(&msg, NULL, 0, 0)) { /*メッセージ取得*/
		if (!IsDialogMessage(hDlg, &msg)){ /*TAB,リターン等を処理*/
			TranslateMessage(&msg);        /*その他のキーボードメッセージを変換*/
			DispatchMessage(&msg);         /*メッセージを各ウィンドウに送る*/
		}
	}
	FreeProcInstance((FARPROC)lpProc);
	return 0;
}
このwhileループはメッセージループといい、Windowsのメッセージ処理の根幹をなす部分です。 実はDialogBox() APIやMessageBox() APIにはこのループとほぼ同じものが内蔵されていたのです。

ダイアログプロシージャでは、ダイアログを閉じるのに、EndDialog()を使ってはいけません。 今までEndDialog()を呼び出していた部分を、DestroyWindow()に変更します。

もしくは自分にWM_CLOSEをSendMessage()する方法でもよいです。 (そしてWM_CLOSE側でDestroyWindowを呼び出す) こういう二段構えの方法を使う理由は、終了確認のメッセージボックスを出す時など それを一箇所にまとめることができるからです。(WM_CLOSEはプロセスの外から(たとえば タスクマネージャから)送られることがあります。) なおWindows自体が終了するときはWM_CLOSEの代わりに WM_QUERYENDSESSINが来るので、終了確認のメッセージを出す場合は、両方のメッセージ に対応する必要があります。

そのダイアログがメインウィンドウの場合は、WM_DESTROYに対して PostQuitMessage()を呼び出します。これはメッセージループを抜けるという動作をします。 (重要かつ忘れやすいので注意)

機能上の違い

モードレスダイアログを使うと、モーダルダイアログに比べて、以下のような利点があります。 具体例は、次回以降でテキストエディタを作っていく中で紹介していきます。

前のページ

次のページ

一つ上のページに戻る