MDI で画像を表示

「新規作成」を選ぶと次々とウインドウが作成されて画像が表示されます。

前田稔(Maeda Minoru)の超初心者のプログラム入門

プログラムの説明

  1. このプログラムは「MDI のプログラム」の続きです。
    メニュー選択でドキュメントウインドウを生成して画像を表示する方法を説明します。
    MDI の詳細は MDI のプログラム を参照して下さい。
  2. #include と #define と Global Area です。
    FrameClassName はフレームウインドウの ClassName です。
    ChildDoc はドキュメントウインドウの ClassName です。
    TITLE はフレームウインドウのタイトルです。
    IDM_FIRSTCHILD はクライアントウインドウのIDです。
    IMG は表示する BMP 画像情報の構造体で、hChild にクライアントウインドウの HWND を格納します。
    doc_no は次に作成するドキュメントウインドウの番号で、現在は10枚分の領域を確保しています。
        #include    <windows.h>
        #include    "resource.h"
        #define     FrameClassName  "MDI"           //フレーム
        #define     ChildDoc        "document"      //ドキュメント
        #define     TITLE           "MDI BMP View"  //ウインドウタイトル
        #define     SAFE_DELDC(p)   { if (p) { DeleteDC (p);   (p)=NULL; } }
        #define     SAFE_DELOBJ(p)  { if (p) { DeleteObject(p); (p)=NULL; } }
        #define     IDM_FIRSTCHILD  100
    
        typedef struct
        {   char        File[MAX_PATH];
            long        Width,Height;
            HWND        hChild;         //Document Class hWnd
            HDC         hBmpDC;         //BMP 画像の HDC
            HBITMAP     hBmp;           //BMP 画像の HBITMAP
        }   IMG;
        IMG             Img[10];
    
        HINSTANCE   g_hInst;
        HWND        hClient;
        HWND        hChild;
        HWND        hFrame;
        HWND        hEdit;
    
        HMENU       hMenuFirst, hMenuDoc;
        HMENU       hMenuFirstWnd, hMenuDocWnd;
        int         doc_no;
        
  3. フレームウインドウの CALLBACK 関数です。
    WinMain() でフレームとドキュメントの Window Class を登録しています。
    WM_CREATE: ではクライアントウインドウを生成します。
    ZeroMemory() で IMG[10] の領域をクリアしています。
    LRESULT CALLBACK FrameWndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
    {   CLIENTCREATESTRUCT  ccs;
        MDICREATESTRUCT     mdic;
        int                 i;
    
        switch (msg)
        {   case WM_CREATE:
                //フレームに続いて、クライアントウインドウを生成する
                ccs.hWindowMenu = hMenuFirstWnd;
                ccs.idFirstChild = IDM_FIRSTCHILD;
                hClient = CreateWindow(
                    "MDICLIENT", NULL,
                    WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN,
                    0, 0, 0, 0,
                    hWnd, (HMENU)1, g_hInst, (LPSTR)&ccs);
                doc_no= 0;
                ZeroMemory(&Img,sizeof(IMG)*10);
                return 0;
        
  4. 新規作成メニューが呼び出されたときの処理です。
    OpenFile() 関数でドキュメントウインドウに描画する BMP File を選択します。
    Img_Load() 関数で BMP File を入力して画像情報を IMG 構造体に設定します。
    BmpFile の選択と入力は BMP ファイルを選択する を参照して下さい。
    次に新しいドキュメントウインドウを生成して、その HWND を IMG の hChild に格納します。
    Title には BMP 画像ファイルの名前を表示しています。
    ドキュメントウインドウに画像を表示するのは、ドキュメントウインドウの CALLBACK 関数で行います。
                switch (LOWORD(wp))
                {   case IDM_NEW:
                        if (doc_no>=10) return 0;
                        //ドキュメントウインドウを作るための情報を設定する
                        if (OpenFile(&Img[doc_no])==FALSE)  return 0;
                        Img_Load(hClient,&Img[doc_no]);
                        mdic.szClass = ChildDoc;
                        mdic.szTitle = Img[doc_no].File;
                        mdic.hOwner = g_hInst;
                        mdic.x = CW_USEDEFAULT;
                        mdic.y = CW_USEDEFAULT;
                        mdic.cx = CW_USEDEFAULT;
                        mdic.cy = CW_USEDEFAULT;
                        mdic.style = 0;
                        mdic.lParam = 0;
                        hChild = (HWND)SendMessage(hClient,WM_MDICREATE,0,(LPARAM)&mdic);
                        Img[doc_no].hChild= hChild;     // Set Document Class hWnd
                        doc_no++;
                        return 0;
        
  5. WM_CLOSE: ではプログラムの終了前に全てのリソースを開放して下さい。
            case WM_QUERYENDSESSION:
            case WM_CLOSE:
                for(i=0; i<10; i++)
                {   SAFE_DELDC(Img[i].hBmpDC);
                    SAFE_DELOBJ(Img[i].hBmp);
                }
                SendMessage(hWnd,WM_COMMAND,IDM_CLOSEALL,0);
                if (GetWindow(hClient, GW_CHILD))   return 0;
                break;
        
  6. ドキュメントウインドウの CALLBACK 関数です。
    この関数は複数のドキュメントウインドウから呼ばれます。
    そこで hWnd と IMG の hChild を比較して、どのウインドウから呼ばれたかを識別します。
    WM_CREATE: では、新しいドキュメントウインドウを生成します。
    WM_PAINT: では hWnd に対応した IMG[] 構造体の画像を描画します。
        // Document CALLBACK 関数
        LRESULT CALLBACK  DocProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
        {   RECT        rc;
            PAINTSTRUCT ps;
            HDC         hdc;
            int         i;
    
            switch (msg)
            {   case WM_CREATE:
                    //ドキュメントウインドウを生成する
                    hClient = GetParent(hWnd);
                    hFrame = GetParent(hClient);
                    GetClientRect(hWnd, &rc);
                    hEdit = CreateWindow(
                        NULL,NULL,WS_VISIBLE | WS_CHILD | ES_WANTRETURN | ES_MULTILINE,
                        rc.left, rc.top,
                        rc.right - rc.left,
                        rc.bottom - rc.top,
                        hWnd, NULL,
                        g_hInst, NULL);
                    return 0;
                case WM_PAINT:
                    for(i=0; i<10 && Img[i].hChild!=hWnd; i++);
                    if (i<10)
                    {   hdc = BeginPaint(hWnd, &ps);
                        if (Img[i].hBmpDC)
                            BitBlt(hdc,0,0,Img[i].Width,Img[i].Height,Img[i].hBmpDC,0,0,SRCCOPY);
                        EndPaint(hWnd, &ps);
                    }
                    break;
                case WM_SIZE:
                    GetClientRect(hWnd,&rc);
                    hEdit = GetWindow(hWnd,GW_CHILD);
                    MoveWindow(hEdit,rc.left,rc.top,rc.right-rc.left,rc.bottom-rc.top,TRUE);
                    break;
                case WM_MDIACTIVATE:
                    if (lp == (LPARAM)hWnd)
                        SendMessage(hClient, WM_MDISETMENU, (WPARAM)hMenuDoc, (LPARAM)hMenuDocWnd);
                    if (lp != (LPARAM)hWnd)
                        SendMessage(hClient, WM_MDISETMENU, (WPARAM)hMenuFirst, (LPARAM)hMenuFirstWnd);
                    DrawMenuBar(hFrame);
                    return 0;
            }
            return (DefMDIChildProc(hWnd, msg, wp, lp));
        }
        

超初心者のプログラム入門(Win32API C++)