マルチドキュメント インターフェイス (MDI) アプリケーションの各ドキュメントは、アプリケーションのメイン ウィンドウのクライアント領域内の個別の子ウィンドウに表示されます。 一般的な MDI アプリケーションには、ユーザーが複数のテキスト ドキュメントを操作できるワープロ アプリケーションと、ユーザーが複数のグラフやスプレッドシートを操作できるようにするスプレッドシート アプリケーションが含まれます。 詳細については、次の各トピックを参照してください。
- フレーム、クライアント、および子ウィンドウ
- 子ウィンドウの作成
- 子ウィンドウのアクティブ化
- 複数のドキュメント メニュー
- 複数のドキュメント アクセラレータ
- 子ウィンドウのサイズと配置
- アイコン タイトル ウィンドウ
- 子ウィンドウ データ
フレーム、クライアント、および子ウィンドウ
MDI アプリケーションには、フレーム ウィンドウ、MDI クライアント ウィンドウ、および多数の子ウィンドウの 3 種類のウィンドウがあります。 フレーム ウィンドウは、アプリケーションのメイン ウィンドウに似ています。サイズ設定の境界線、タイトル バー、ウィンドウ メニュー、最小化ボタン、最大化ボタンがあります。 アプリケーションでは、フレーム ウィンドウのウィンドウ クラスを登録し、それをサポートするウィンドウ プロシージャを提供する必要があります。
MDI アプリケーションは、フレーム ウィンドウのクライアント領域に出力を表示しません。 代わりに、MDI クライアント ウィンドウが表示されます。 MDI クライアント ウィンドウは、事前登録されたウィンドウ クラス MDICLIENT に属する特殊な種類の子ウィンドウです。 クライアント ウィンドウはフレーム ウィンドウの子です。子ウィンドウの背景として機能します。 また、子ウィンドウの作成と操作のサポートも提供します。 たとえば、MDI アプリケーションは、MDI クライアント ウィンドウにメッセージを送信することで、子ウィンドウを作成、アクティブ化、または最大化できます。
ユーザーがドキュメントを開くか作成すると、クライアント ウィンドウによってドキュメントの子ウィンドウが作成されます。 クライアント ウィンドウは、アプリケーション内のすべての MDI 子ウィンドウの親ウィンドウです。 各子ウィンドウには、サイズ変更の境界線、タイトル バー、ウィンドウ メニュー、最小化ボタン、最大化ボタンがあります。 子ウィンドウはクリップされるため、クライアント ウィンドウに限定され、外部に表示することはできません。
MDI アプリケーションは、複数の種類のドキュメントをサポートできます。 たとえば、一般的なスプレッドシート アプリケーションを使用すると、ユーザーはグラフとスプレッドシートの両方を操作できます。 MDI アプリケーションは、サポートするドキュメントの種類ごとに、子ウィンドウ クラスを登録し、そのクラスに属するウィンドウをサポートするウィンドウ プロシージャを提供する必要があります。 ウィンドウ クラスの詳細については、「ウィンドウ クラス 」を参照してください。 ウィンドウ プロシージャの詳細については、「 ウィンドウ プロシージャ」を参照してください。
一般的な MDI アプリケーションを次に示します。 これは Multipad という名前です。
子ウィンドウの作成
子ウィンドウを作成するには、MDI アプリケーションが CreateMDIWindow 関数を呼び出すか、 WM_MDICREATE メッセージを MDI クライアント ウィンドウに送信します。 MDI 子ウィンドウを作成するより効率的な方法は、 CreateWindowEx 関数を呼び出して、 WS_EX_MDICHILD 拡張スタイルを指定することです。
子ウィンドウを破棄するために、MDI アプリケーションは WM_MDIDESTROY メッセージを MDI クライアント ウィンドウに送信します。
子ウィンドウのアクティブ化
クライアント ウィンドウには任意の数の子ウィンドウを一度に表示できますが、アクティブにできるのは 1 つだけです。 アクティブな子ウィンドウは、他のすべての子ウィンドウの前に配置され、その境界線が強調表示されます。
ユーザーは、非アクティブな子ウィンドウをクリックしてアクティブ化できます。 MDI アプリケーションは、 WM_MDIACTIVATE メッセージを MDI クライアント ウィンドウに送信することで、子ウィンドウをアクティブにします。 クライアント ウィンドウは、このメッセージを処理すると、 アクティブ 化する子ウィンドウのウィンドウ プロシージャと非アクティブ化される子ウィンドウのウィンドウ プロシージャに、WM_MDIACTIVATE メッセージを送信します。
子ウィンドウがアクティブ化されないようにするには、FALSE を返して子ウィンドウにWM_NCACTIVATE メッセージを処理します。
システムは、重なり合うウィンドウのスタック内の各子ウィンドウの位置を追跡します。 この積み重ねは Z オーダーと呼ばれます。 ユーザーは、アクティブ ウィンドウのウィンドウ メニューから [ 次へ ] をクリックして、Z オーダーで次の子ウィンドウをアクティブ化できます。 アプリケーションは、 WM_MDINEXT メッセージを クライアント ウィンドウに送信することで、Z オーダーで次の (または前の) 子ウィンドウをアクティブ化します。
アクティブな子ウィンドウにハンドルを取得するために、MDI アプリケーションはクライアント ウィンドウ にWM_MDIGETACTIVE メッセージを送信します。
複数のドキュメント メニュー
MDI アプリケーションのフレーム ウィンドウには、ウィンドウ メニューを含むメニュー バーが含まれている必要があります。 ウィンドウ メニューには、クライアント ウィンドウ内に子ウィンドウを配置する項目、またはすべての子ウィンドウを閉じる項目が含まれている必要があります。 一般的な MDI アプリケーションのウィンドウ メニューには、次の表の項目が含まれている場合があります。
| メニュー項目 | 目的 |
|---|---|
| タイル | 子ウィンドウをタイル形式で配置し、それぞれがクライアント ウィンドウ全体に表示されるようにします。 |
| カスケード | 子ウィンドウをカスケード形式で配置します。 子ウィンドウは互いに重なっていますが、それぞれのタイトル バーが表示されます。 |
| アイコンの配置 | 最小化された子ウィンドウのアイコンをクライアント ウィンドウの下部に配置します。 |
| すべて閉じる | すべての子ウィンドウを閉じます。 |
子ウィンドウが作成されるたびに、新しいメニュー項目がウィンドウ メニューに自動的に追加されます。 メニュー項目のテキストは、新しい子ウィンドウのメニュー バーのテキストと同じです。 メニュー項目をクリックすると、ユーザーは対応する子ウィンドウをアクティブ化できます。 子ウィンドウが破棄されると、対応するメニュー項目がウィンドウ メニューから自動的に削除されます。
システムは、ウィンドウ メニューに最大 10 個のメニュー項目を追加できます。 10 番目の子ウィンドウが作成されると、その 他の Windows 項目がウィンドウ メニューに追加されます。 この項目をクリックすると、[ ウィンドウの選択 ] ダイアログ ボックスが表示されます。 このダイアログ ボックスには、現在使用可能なすべての MDI 子ウィンドウのタイトルを含むリスト ボックスが含まれています。 ユーザーは、リスト ボックス内のタイトルをクリックして、子ウィンドウをアクティブ化できます。
MDI アプリケーションで複数の種類の子ウィンドウがサポートされている場合は、アクティブ ウィンドウに関連付けられている操作を反映するようにメニュー バーを調整します。 これを行うには、アプリケーションがサポートする子ウィンドウの種類ごとに個別のメニュー リソースを指定します。 新しい種類の子ウィンドウがアクティブになると、アプリケーションはクライアント ウィンドウ にWM_MDISETMENU メッセージを送信し、対応するメニューにハンドルを渡す必要があります。
子ウィンドウが存在しない場合、メニュー バーには、ドキュメントの作成または開きに使用する項目のみが含まれている必要があります。
ユーザーがカーソル キーを使用して MDI アプリケーションのメニュー内を移動する場合、キーの動作は、ユーザーが一般的なアプリケーションのメニュー内を移動する場合とは異なります。 MDI アプリケーションでは、コントロールはアプリケーションのウィンドウ メニューからアクティブな子ウィンドウのウィンドウ メニューに、次にメニュー バーの最初の項目に渡されます。
複数のドキュメント アクセラレータ
子ウィンドウのアクセラレータ キーを受信して処理するには、MDI アプリケーションのメッセージ ループに TranslateMDISysAccel 関数を含める必要があります。 このループでは、TranslateAccelerator または DispatchMessage 関数を呼び出す前に TranslateMDISysAccel を呼び出す必要があります。
MDI 子ウィンドウのウィンドウ メニューのアクセラレータ キーは、MDI 以外の子ウィンドウのキーとは異なります。 MDI 子ウィンドウでは、Alt + - (マイナス) キーの組み合わせによってウィンドウ メニューが開き、Ctrl + F4 キーの組み合わせによってアクティブな子ウィンドウが閉じられ、Ctrl + F6 キーの組み合わせによって次の子ウィンドウがアクティブになります。
子ウィンドウのサイズと配置
MDI アプリケーションは、MDI クライアント ウィンドウにメッセージを送信することによって、子ウィンドウのサイズと位置を制御します。 アクティブな子ウィンドウを最大化するために、アプリケーションは WM_MDIMAXIMIZE メッセージをクライアント ウィンドウに送信します。 子ウィンドウが最大化されると、そのクライアント領域が MDI クライアント ウィンドウ全体に表示されます。 さらに、子ウィンドウのタイトル バーが自動的に非表示になり、子ウィンドウのウィンドウ メニュー アイコンと [復元] ボタンが MDI アプリケーションのメニュー バーに追加されます。 アプリケーションは、クライアント ウィンドウに WM_MDIRESTORE メッセージを送信することで、クライアント ウィンドウを元の (最大サイズに) サイズと位置に復元できます。
MDI アプリケーションでは、子ウィンドウをカスケード形式またはタイル形式で配置できます。 子ウィンドウがカスケードされると、ウィンドウが重ねて表示されます。 スタックの下部にあるウィンドウは画面の左上隅を占め、残りのウィンドウは垂直方向と水平方向にオフセットされ、各子ウィンドウの左罫線とタイトル バーが表示されます。 子ウィンドウをカスケード形式で配置するために、MDI アプリケーションは WM_MDICASCADE メッセージを送信します。 通常、アプリケーションは、ユーザーがウィンドウ メニューの [カスケード ] をクリックすると、このメッセージを送信します。
子ウィンドウがタイル化されると、各子ウィンドウ全体が表示され、どのウィンドウも重なっていない状態になります。 すべてのウィンドウは、必要に応じて、クライアント ウィンドウ内に収まるようにサイズ設定されます。 子ウィンドウをタイル形式で配置するために、MDI アプリケーションは WM_MDITILE メッセージをクライアント ウィンドウに送信します。 通常、アプリケーションは、ユーザーがウィンドウ メニューの [タイル ] をクリックすると、このメッセージを送信します。
MDI アプリケーションは、サポートする子ウィンドウの種類ごとに異なるアイコンを提供する必要があります。 アプリケーションは、子ウィンドウ クラスを登録するときにアイコンを指定します。 子ウィンドウが最小化されると、クライアント ウィンドウの下部に子ウィンドウのアイコンが自動的に表示されます。 MDI アプリケーションは、 WM_MDIICONARRANGE メッセージを クライアント ウィンドウに送信することで、子ウィンドウアイコンを配置するようにシステムに指示します。 通常、アプリケーションは、ユーザーがウィンドウ メニューの [アイコンの配置 ] をクリックすると、このメッセージを送信します。
アイコン タイトル ウィンドウ
MDI 子ウィンドウは最小化される可能性があるため、MDI アプリケーションでは、アイコン タイトル ウィンドウを通常の MDI 子ウィンドウのように操作しないようにする必要があります。 アイコン タイトル ウィンドウは、アプリケーションが MDI クライアント ウィンドウの子ウィンドウを列挙するときに表示されます。 アイコン タイトル ウィンドウは他の子ウィンドウとは異なりますが、MDI 子ウィンドウによって所有されています。
子ウィンドウがアイコン のタイトル ウィンドウかどうかを確認するには、GW_OWNER インデックスで GetWindow 関数を使用します。 タイトル以外のウィンドウは NULL を返します。 メニューとダイアログ ボックスは所有ウィンドウであるため、最上位レベルのウィンドウではこのテストが不十分であることに注意してください。
子ウィンドウ データ
子ウィンドウの数はユーザーが開くドキュメントの数によって異なるため、MDI アプリケーションはデータ (現在のファイルの名前など) を各子ウィンドウに関連付ける必要があります。 これを行うには、次の 2 つの方法があります。
- 子ウィンドウ のデータをウィンドウ構造に格納します。
- ウィンドウのプロパティを使用します。
ウィンドウ構造
MDI アプリケーションは、ウィンドウ クラスを登録するときに、ウィンドウのこの特定のクラスに固有のアプリケーション データのウィンドウ構造に余分な領域を予約することがあります。 この余分な領域にデータを格納および取得するために、アプリケーションは GetWindowLong 関数と SetWindowLong 関数を 使用します。
子ウィンドウに大量のデータを保持するために、アプリケーションはデータ構造のメモリを割り当て、その構造体を含むメモリに子ウィンドウに関連付けられている余分な領域にハンドルを格納できます。
ウィンドウのプロパティ
MDI アプリケーションでは、ウィンドウ プロパティを使用してドキュメントごとのデータを格納することもできます。 ドキュメントごとのデータ は、特定の子ウィンドウに含まれるドキュメントの種類に固有のデータです。 プロパティは、ウィンドウ クラスを登録するときに余分な領域を割り当てる必要がないという点で、ウィンドウ構造の余分な領域とは異なります。 ウィンドウには任意の数のプロパティを含めることができます。 また、オフセットを使用してウィンドウ構造内の余分なスペースにアクセスする場合、プロパティは文字列名によって参照されます。 ウィンドウのプロパティの詳細については、「 ウィンドウのプロパティ」を参照してください。