アークピットのホームページに戻る

WinAPIトピックのトップページに戻る

APIトピックの各章に移動する

ダウンロードのページに移動する
ダウンロードができ
ない場合の対処法
 

ページ移動

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 に渡すパラメータです。
 ただスタイルは、MDIS_ALLCHILDSTYLES を付加するときは、CreateWindow 関数と同じ WS_XXX を指定します。しかしこれが無い時は、MDIのデフォルトのスタイルになります。ただし WS_MINIMIZE,WS_MAXIMIZE,WS_HSCROLL,WS_VSCROLL の4つは指定できます。WS_MINIMIZE を指定すれば、最小化で作成され、WS_MAXIMIZE なら最大化で作成されます。WS_HSCROLL,WS_VSCROLL はスクロールバーを付けたウィンドウを作成します。
 また最後の WM_CREATE に渡すパラメータは、CreateMDIWindow の渡す側は、CreateWindow と同じですが、受け取る側は異なります。これは、次節の2-4-9. MDI子ウィンドウのプロシージャで説明します。

ページ移動