|
|
|
2-4-8. MDI子ウィンドウの作成MDIクライアントウィンドウを作成できたら、次はMDI子ウィンドウの作成です。子ウィンドウは、システムが自動的に作成することもありますが、通常は、コマンドで利用者の操作によって作成を行ないます。ApMdisysでもファイルメニューで作成します。MDIの場合は、MDI子ウィンドウのことをドキュメントウィンドウと呼びます。MDI子ウィンドウのウィンドウクラスを登録する MDIの子ウィンドウもウィンドウプロシージャを使用しますので、まずウィンドウクラスを登録しなければいけません。 : (他のコード)
// Hello MDI子ウィンドウのクラスの登録
wc.lpfnWndProc = (WNDPROC)HelloProc;
wc.cbWndExtra = sizeof(LONG);
wc.hIcon = LoadIcon(hInstance,MAKEINTRESOURCE(IDI_HELLO));
wc.lpszClassName = pHelloClass;
wc.hIconSm = LoadImage(hInstance,MAKEINTRESOURCE(IDI_HELLO),
IMAGE_ICON,16,16,LR_DEFAULTCOLOR);
if (!RegisterClassEx(&wc)) return FALSE;
// リッチテキストMDI子ウィンドウのクラスの登録
wc.lpfnWndProc = (WNDPROC)ReditProc;
wc.cbWndExtra = sizeof(LONG);
wc.hIcon = LoadIcon(hInstance,MAKEINTRESOURCE(IDI_REDIT));
wc.lpszClassName = pReditClass;
wc.hIconSm = LoadImage(hInstance,MAKEINTRESOURCE(IDI_REDIT),
IMAGE_ICON,16,16,LR_DEFAULTCOLOR);
if (!RegisterClassEx(&wc)) return FALSE;
: (他のコード)
WNDCLASSEX のすべてのメンバに設定していませんが、フレームウィンドウと同じ内容は省略しています。まず、lpfnWndProc のプロシージャのアドレスと、lpszClassName のクラス名を設定します。また、hIcon と hIconSm の2つの大小のアイコンは個別の設定を行ないます。ちなみに、pHelloClass や pReditClass は複数の場所で使用しますので、"HelloClass" などの実体を使用しないで、変数で指定します。
MDIで一番活躍するのが、cbWndExtra のウィンドウの補足メモリブロックです。2-2-10. 補足メモリブロックの使用例でも説明しましたが、MDIの場合は、1つのプロシージャを使って複数のウィンドウを作成する可能性が高くなります。ApMdisysでもApHelloとApReditのウィンドウはいくつでも作成できます。よってウィンドウに固有のパラメータは、プロシージャ内で static 変数では設定できません。ApHelloの場合は、左・中央・右の配置方の値を補足メモリブロックに設定します。ApReditの場合は、リッチテキストコントロールを使用しますが、そのウィンドウハンドルを補足メモリブロックに設定します。これで、GetWindowLong 関数でそれらのパラメータを得ることができます。 MDI子ウィンドウの作成する2つの方法 実はMDI子ウィンドウを作成する方法は2つあります。CreateMDIWindow 関数をコールする方法と、MDIクライアントウィンドウに、WM_MDICREATE メッセージを送信する方法です。WM_MDICREATE は、MDICREATESTRUCT 構造体を使用するのでやや面倒です。CreateMDIWindow 関数を使った方が簡単でしょう。しかしこれらは、構造体のメンバが、CreateMDIWindow 関数のパラメータになっていますので、どちらもまったく同じ内容で、しかも結果も同じです。MDI子ウィンドウの作成する ApMdisysには2つのMDI子ウィンドウがあります。ApHelloとApReditです。それらは、ファイルメニューの「Helloウィンドウの新規作成」と「文章ウィンドウの新規作成」コマンドで作成します。またApReditは、作成してファイルをロードする「開く」コマンドもあります。 : (他のコード)
case WM_COMMAND: // メニューやアクセラレータのコマンド
{
switch (LOWORD(wParam))
{
//
// [ファイル(F)]のメニュー項目
//
case IDM_NEWHELLO: // Helloウィンドウの新規作成
{
CreateMDIWindow(pHelloClass,pHelloApp,0,
CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,CW_USEDEFAULT,
hWndClient,
(HINSTANCE)GetWindowLong(hWnd,GWL_HINSTANCE),
0);
break;
}
case IDM_NEWREDIT: // 文章ウィンドウの新規作成
{
MDICREATESTRUCT mdic;
mdic.szClass = pReditClass;
mdic.szTitle = pReditApp;
mdic.hOwner = (HINSTANCE)GetWindowLong(hWnd,
GWL_HINSTANCE);
mdic.x = mdic.y = CW_USEDEFAULT;
mdic.cx = mdic.cy = CW_USEDEFAULT;
mdic.style = 0;
mdic.lParam = 0;
SendMessage(hWndClient,WM_MDICREATE
,0,(LPARAM)&mdic);
break;
}
case IDM_OPEN: // ファイルの表示
{
OPENFILENAME ofn;
TCHAR szFileName[MAX_PATH];
szFileName[0] = '\0';
// OPENFILENAME構造体を設定する。
ZeroMemory(&ofn,sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = hWnd;
ofn.lpstrFilter = "全ファイル形式(*.*)\0*.*\0"
"テキストファイル形式(*.txt)\0*.txt\0"
"プログラムファイル形式(*.c,*.h)\0"
"*.c;*.h;*.cpp;*.rc;*.mak\0\0";
ofn.lpstrFile = szFileName;
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_FILEMUSTEXIST|OFN_ENABLEHOOK
|OFN_EXPLORER|OFN_HIDEREADONLY;
ofn.lpstrDefExt = "txt";
if (!GetOpenFileName(&ofn)) break; // キャンセル
CreateMDIWindow(pReditClass,pReditApp,0,
CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,CW_USEDEFAULT,
hWndClient,
(HINSTANCE)GetWindowLong(hWnd,GWL_HINSTANCE),
(LPARAM)szFileName);
break;
}
: (他のコード)
MDI子ウィンドウを作成する方法は2つあると言いましたが、IDM_NEWHELLO と IDM_OPEN では、CreateMDIWindow 関数をコールする方法を使用しています。そして、IDM_NEWREDIT では、MDIクライアントウィンドウに、WM_MDICREATE メッセージを送信する方法を使用しています。
CreateMDIWindow も MDICREATESTRUCT もほぼ CreateWindow 関数に準拠していますので、内容は理解できると思います。ウィンドウクラス名、タイトル、スタイル、位置にサイズ、親ウィンドウ(MDIクライアントウィンドウ)のハンドル、HINSTANCE、最後が WM_CREATE に渡すパラメータです。
|