MDI子ウィンドウの操作
MDI子ウィンドウのメッセージ
MDI子ウィンドウを操作するために、以下のメッセージが用意されています。
これらのメッセージは全てクライアントウィドウに送信します。
メッセージ | WPARAM | LPARAM | 戻り値 |
---|---|---|---|
WM_MDIACTIVATE | MDI子ウィンドウハンドル | 0 | 0 |
(送信)
(受信) |
|||
WM_MDINEXT | MDI子ウィンドウハンドル | 対象のウィンドウを示す値 (説明を参照) |
0 |
指定のMDI子ウィンドウの前または次の子ウィンドウをアクティブにする。
LPARAMが0の場合、WPARAMで指定した子ウィンドウの次のウィンドウをアクティブにする。 |
|||
WM_MDIGETACTIVE | 0 | 子ウィンドウの最大化状態を格納するBOOL型のポインタ ( NULL も可) |
MDI子ウィンドウハンドル |
現在アクティブになっているMDI子ウィンドウのハンドルを取得する。
LPARAMには子ウィンドウの最大化状態を格納するBOOL型変数のポインタを指定する。 |
|||
WM_MDICASCADE | 0または整列方法を示す定数 (説明を参照) |
0 | 成功した場合はTRUE 失敗した場合は FALSE |
MDI子ウィンドウを重ねて整列する。
WPARAMは以下の定数の組み合わせを指定できる。 |
|||
WM_MDITILE | 整列方法を示す定数 (説明を参照) |
0 | 成功した場合はTRUE 失敗した場合は FALSE |
MDI子ウィンドウを並べて整列する。
WPARAMは以下の定数の組み合わせを指定する。 |
|||
WM_MDIICONARRANGE | 0 | 0 | MDI子ウィンドウハンドル |
最小化されている全てのMDI子ウィンドウを整列する。 |
|||
WM_MDIMAXIMIZE | MDI子ウィンドウハンドル | 0 | 0 |
指定のMDI子ウィンドウを最大化する。 |
|||
WM_MDIRESTORE | MDI子ウィンドウハンドル | 0 | 0 |
指定のMDI子ウィンドウの最大化/最小化状態を元に戻す。 |
|||
WM_MDICREATE | 0 | MDICREATESTRUCT構造体へのポインタ | 成功した場合は作成した子ウィンドウのハンドル 失敗した場合は NULL |
MDI子ウィンドウを作成する。 |
|||
WM_MDIDESTROY | MDI子ウィンドウのハンドル | 0 | 0 |
MDI子ウィンドウを破棄する。 |
|||
WM_MDISETMENU | メニューハンドル (フレームウィンドウ) |
メニューハンドル (ウィンドウメニュー) |
古いフレームウィンドウのメニューハンドル 失敗した場合は0 |
フレームウィンドウのメニューを
※ここで言うウィンドウメニューとは、MDI子ウィンドウの一覧が表示されるサブメニューのこと。 |
|||
WM_MDIREFRESHMENU | 0 | 0 | フレームウィンドウのメニューハンドル 失敗した場合は0 |
フレームウィンドウのウィンドウメニューを更新する。 |
子ウィンドウ操作の例
上記のメッセージを利用した、子ウィンドウの操作例です。
メニューの各項目の表示の通りの操作が可能です。
/////////////////////////////////////////////////////////////////////////////
//
// Menu
//
IDR_MENU1 MENU
BEGIN
POPUP "ファイル(&F)"
BEGIN
MENUITEM "終了(&X)", ID_QUIT
END
POPUP "ウィンドウ(&W)"
BEGIN
MENUITEM "新規作成(&N)", ID_CREATECHILD
MENUITEM SEPARATOR
POPUP "整列"
BEGIN
MENUITEM "重ねる(&C)", ID_MDICASCADE
MENUITEM "水平に並べる(&H)", ID_MDITILEH
MENUITEM "垂直に並べる(&V)", ID_MDITILEV
END
MENUITEM "次のウィンドウ(&F)", ID_MDINEXT
MENUITEM "前のウィンドウ(&B)", ID_MDIPREV
MENUITEM "最大化/元に戻す(&M)", ID_MDIMAXIMIZE
MENUITEM "閉じる(&C)", ID_MDIDESTROY
MENUITEM "全て閉じる(&A)", ID_MDICLOSEALL
END
END
#include <windows.h>
#include "resource.h"
#define ID_MDICHILDFIRST 200
//グローバル変数
HWND hClientWnd;
//関数プロトタイプ宣言
//ウィンドウプロシージャ
LRESULT CALLBACK FrameWndProc(HWND, UINT, WPARAM, LPARAM);
//MDI子ウィンドウプロシージャ
LRESULT CALLBACK DocProc(HWND, UINT, WPARAM, LPARAM);
//子ウィンドウの列挙
BOOL CALLBACK EnumChildProc(HWND, LPARAM);
//ウィンドウの生成等は省略
//フレームウィンドウプロシージャ
LRESULT CALLBACK FrameWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
CLIENTCREATESTRUCT ccs;
HWND h;
BOOL b;
switch (message)
{
case WM_CREATE:
//クライアントウィンドウの作成
ccs.hWindowMenu = GetSubMenu(GetMenu(hWnd), 1);
ccs.idFirstChild = ID_MDICHILDFIRST;
hClientWnd = CreateWindow(L"MDICLIENT", NULL,
WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL,
0, 0, 0, 0, hWnd, (HMENU)1, hInst, &ccs);
return 0;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case ID_QUIT: //終了
SendMessage(hWnd, WM_CLOSE, 0, 0);
return 0;
case ID_CREATECHILD: //子ウィンドウ作成
h = CreateMDIWindow(szWindowClass_MDIChild, L"MDI子ウィンドウ", 0,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
hClientWnd, hInst, NULL);
return 0;
case ID_MDICASCADE: //重ねて整列
SendMessage(hClientWnd, WM_MDICASCADE, 0, 0);
return 0;
case ID_MDITILEH: //水平に整列
SendMessage(hClientWnd, WM_MDITILE, MDITILE_HORIZONTAL, 0);
return 0;
case ID_MDITILEV: //垂直に整列
SendMessage(hClientWnd, WM_MDITILE, MDITILE_VERTICAL, 0);
return 0;
case ID_MDINEXT: //次のウィンドウ
h = (HWND)SendMessage(hClientWnd, WM_MDIGETACTIVE, 0, 0);
if (h)
{
SendMessage(hClientWnd, WM_MDINEXT, (WPARAM)h, 0);
}
return 0;
case ID_MDIPREV: //前のウィンドウ
h = (HWND)SendMessage(hClientWnd, WM_MDIGETACTIVE, 0, 0);
if (h)
{
SendMessage(hClientWnd, WM_MDINEXT, (WPARAM)h, 1);
}
return 0;
case ID_MDIMAXIMIZE: //最大化/元に戻す
h = (HWND)SendMessage(hClientWnd, WM_MDIGETACTIVE, 0, &b);
if (h)
{
SendMessage(hClientWnd, b ? WM_MDIRESTORE : WM_MDIMAXIMIZE, (WPARAM)h, 0);
}
return 0;
case ID_MDIDESTROY: //閉じる
h = (HWND)SendMessage(hClientWnd, WM_MDIGETACTIVE, 0, 0);
if (h)
{
SendMessage(hClientWnd, WM_MDIDESTROY, (WPARAM)h, 0);
}
return 0;
case ID_MDICLOSEALL: //全て閉じる
EnumChildWindows(hClientWnd, EnumChildProc, ID_MDICLOSEALL);
return 0;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefFrameProc(hWnd, hClientWnd, message, wParam, lParam);
}
//子ウィンドウプロシージャ
LRESULT CALLBACK DocProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
//省略
}
//子ウィンドウの列挙
BOOL CALLBACK EnumChildProc(HWND hWnd, LPARAM lParam) {
switch (lParam)
{
case ID_MDICLOSEALL: //全て閉じる
SendMessage(hClientWnd, WM_MDIDESTROY, (LPARAM)hWnd, 0);
break;
}
return TRUE;
}
全ての子ウィンドウを閉じる
MDI子ウィンドウメッセージには「全ての子ウィンドウを閉じる」というものはありません。
しかしそういった処理をしたい場合もあると思うので、上記サンプルコードにはその実装例を示しています。
//該当箇所のみ抜粋
LRESULT CALLBACK FrameWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
case WM_COMMAND:
switch (LOWORD(wParam))
{
case ID_MDICLOSEALL: //全て閉じる
EnumChildWindows(hClientWnd, EnumChildProc, ID_MDICLOSEALL);
return 0;
}
}
return DefFrameProc(hWnd, hClientWnd, message, wParam, lParam);
}
BOOL CALLBACK EnumChildProc(HWND hWnd, LPARAM lParam) {
switch (lParam)
{
case ID_MDICLOSEALL: //全て閉じる
SendMessage(hClientWnd, WM_MDIDESTROY, (LPARAM)hWnd, 0);
break;
}
return TRUE;
}
EnumChildWindows
関数は、全ての子ウィンドウに対して一度ずつ処理を行います。
- BOOL EnumChildWindows(
HWND hWndParent,
WNDENUMPROC lpEnumFunc,
LPARAM lParam
); - ウィンドウhWndParentの全ての子ウィンドウに対して関数lpEnumFuncを実行する。
追加の情報をlParamに格納できる。
戻り値は使用しない。
第一引数hWndParent
は親ウィンドウハンドルです。
クライアントウィンドウのハンドルを指定すると、全てのMDI子ウィンドウが対象になります。
第二引数lpEnumFunc
は適用する処理のコールバック関数へのポインタです。
第三引数lParam
はコールバック関数に渡す追加の情報です。
第二引数に指定するコールバック関数は以下の形で定義します。
- BOOL CALLBACK EnumChildProc(
HWND hwnd,
LPARAM lParam
); - EnumChildWindows関数で使用されるコールバック関数の関数定義。
第一引数hwnd
には操作対象の子ウィンドウハンドルが格納されます。
第二引数lParam
はEnumChildWindows関数の第三引数に指定した値が格納されます。
上記コードのコールバック関数では、lParamが「ID_MDICLOSEALL」ならば、クライアントウィンドウにWM_MDIDESTROY
メッセージを送信して自分自身(子ウィンドウ)を破棄しています。
全ての子ウィンドウに対して同様の処理が順に実行されます。
(今回は破棄以外の動作はしないのでlParamをチェックする処理は無くても同じです)
このコールバック関数はTRUE
を返すと処理を続行します。
(次のウィンドウの処理を開始する)
FALSE
を返すと処理を中断します。
今回は常にTRUEを返すので、全ての子ウィンドウの列挙が終わるまで処理は継続されます。