モードレス Dialog で画像アイコンをクリック

VC++ でモードレス Dialog Box のアイコンをクリックして画像を切り替えます。

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

プロジェクトの設定

  1. 6枚の BMP 画像と対応するアイコンを用意して下さい。
    新規プロジェクトからテンプレートを使って(MDless)を作成して下さい。
    用意した6枚の BMP 画像と対応するアイコンをプロジェクトのフォルダーに格納して下さい。
    [プロジェクト] [リソースの追加] [Icon] [インポート] で6枚のアイコンを取り込みます。
  2. 画像を参考にして[ピクチャーコントロール]と[ラジオボタン]と[Button]を配置して下さい。
    説明の画像
  3. 次の表に合わせて「キャプションとID(Image)」を設定して下さい。
    PictureControl を選択して Type からアイコンを選択すると、リソースとして取り込んだアイコンを選択することができます。
    BOX キャプション ID(Image)
    DialogBox ダイアログ IDD_DIALOG1
    PictureControl IDI_ICON1
    PictureControl IDI_ICON2
    PictureControl IDI_ICON3
    PictureControl IDI_ICON4
    PictureControl IDI_ICON5
    PictureControl IDI_ICON6
    RadioButton IDC_RADIO1
    RadioButton IDC_RADIO2
    RadioButton IDC_RADIO3
    RadioButton IDC_RADIO4
    RadioButton IDC_RADIO5
    RadioButton IDC_RADIO6
    Button OK IDOK
    Button キャンセル IDCANCEL
  4. ラジオボタンはグループ内で一個だけ選択できるようになっているので、今回のように DialogBox 全体で一個だけ選択する 場合には以下の操作は不要かも知れません。
    6個のアイコンとラジオボタンをグループで囲んで、グループ内から一個だけラジオボタンを選択できるようにします。
    [書式(レイアウト)][タブオーダー]でグループ内のラジオボタンを順番にクリックして並べて下さい。
    1番と7番のボックスのプロパティでグループをチェック(True)にします。
    7番(キャンセル)はグループの終わり(次のグループの始まり)を指示するために必要です。
    説明の画像
  5. my.lib に登録されている BMP Object Class を使っています。
    読者諸氏が作成するときは Object Class Library から次のファイルを取得してプロジェクトに組み込んで下さい。
    ファイル名 説明
    image.h IMAGE Object Class のヘッダファイル
    image.cpp IMAGE Object Class のプログラムファイル
    IMAGE Object Class を使うと BMP 画像だけで無く、JPG や GIF 画像も使えるようになります。
  6. ソースプログラムを表示して下さい。
    windowsx.h と my.h を取り込みます。
    hDlg は Dialog Box のハンドルです。
    nCF[6]; ID[6] はラジオボタンのステータスを取得するための領域です。
    *Bmp[6]; name[6][16] は BMP 画像を表示するための領域です。
        #include    "stdafx.h"
        #include    <windowsx.h>
        #include    "resource.h"
        #include    "Main.h"
        #include    "my.h"
    
        #define MAX_LOADSTRING 100
    
        // グローバル変数:
        HINSTANCE hInst;                        // 現在のインスタンス
        TCHAR szTitle[MAX_LOADSTRING];          // タイトル バー テキスト
        TCHAR szWindowClass[MAX_LOADSTRING];    // タイトル バー テキスト
    
        HWND    hDlg;
        int     nCF[6];                 //ラジオボタンの情報を設定する
        int     ID[6]=
        {   IDC_RADIO1,IDC_RADIO2,IDC_RADIO3,IDC_RADIO4,IDC_RADIO5,IDC_RADIO6   };
    
        BMP     *Bmp[6];                //BitMap Object
        char    name[6][16]=
        {  "RINA.BMP", "EMIKO.BMP", "GEO.BMP", "MOSQUIT.BMP", "NANAO.BMP", "DORAEMON.BMP"  };
        
  7. このプログラムで使用する関数を定義します。
    関数定義の説明は 円を描画する関数を作成する を参照して下さい。
    IMAGE Object Class を使うときは、Class に合わせてソースコードを修正して下さい。
            for(i=0; i<6; i++)
            {   Bmp[i]= new IMAGE(hWnd);
                Bmp[i]->LoadFile(name[i]);
            }
        
        // このコード モジュールに含まれる関数の宣言を転送します :
        ATOM                MyRegisterClass(HINSTANCE hInstance);
        BOOL                InitInstance(HINSTANCE, int);
        LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
        LRESULT CALLBACK    About(HWND, UINT, WPARAM, LPARAM);
    
        LRESULT CALLBACK    MyDlgProc(HWND, UINT, WPARAM, LPARAM);
        int                 InitApp(HWND);
        int                 GetMyDlg();
    
        //★ Application の初期設定
        int InitApp(HWND hWnd)
        {   int i;
    
            for(i=0; i<6; i++)
            {   Bmp[i]= new BMP(hWnd);
                Bmp[i]->Load(name[i]);
            }
            return 0;
        }
    
        //★ ラジオボタンの情報を nCF[i] に設定する
        int GetMyDlg()
        {   int     i;
    
            for(i=0; i<6; i++)
                nCF[i] = Button_GetCheck(GetDlgItem(hDlg,ID[i]));
            return i;
        }
    
        //★ DialogBox の CALLBACK 関数
        LRESULT CALLBACK MyDlgProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
        {   static HWND hParent;
    
            hParent = GetParent(hWnd);
            switch(msg)
            {   case WM_INITDIALOG:
                    Button_SetCheck(GetDlgItem(hWnd,IDC_RADIO6),BST_CHECKED);
                    return TRUE;
                case WM_COMMAND:
                    switch(LOWORD(wp))
                    {   case IDOK:
                            GetMyDlg();
                            InvalidateRect(hParent, NULL, TRUE); 
                            return TRUE;
                        case IDCANCEL:
                            SendMessage(hParent, WM_CLOSE, 0, 0L);
                            return TRUE;
                    }
            }
            return FALSE;
        }
        
  8. InitInstance() の位置までスクロールします。
    ここに Modeless Dialog Box を表示するコードを記述します。
         if( !hWnd ) 
         {
            return FALSE;
         }
         hDlg = CreateDialog(hInst,MAKEINTRESOURCE(IDD_DIALOG1),hWnd,(DLGPROC)MyDlgProc);
         if (hDlg == NULL)    return FALSE;
    
         ShowWindow( hWnd, nCmdShow );
         UpdateWindow( hWnd );
         ShowWindow(hDlg, SW_SHOW);
         UpdateWindow(hDlg);
        
  9. WndProc() に WM_CREATE: と WM_CLOSE: を追加します。
    WM_PAINT: に画像を描画するコードを書きます。
        switch (message)
        {
        case WM_CREATE:
            InitApp(hWnd);
            break;
              :
              :
        case WM_PAINT:
            hdc = BeginPaint (hWnd, &ps);
            // TODO: この位置に描画用のコードを追加してください...
            for(i=0; i<5 && nCF[i]==0; i++);
            Bmp[i]->Show(hdc);
            EndPaint( hWnd, &ps );
            break;
        case WM_CLOSE:
            for(i=0; i<6; i++)   SAFE_DELETE(Bmp[i]);
            DestroyWindow(hWnd);
            break;
        

プログラムの説明

モードレス・ダイアログボックスは常に表示したまま MainWindow の操作などができる DialogBox です。
DialogBox に画像のアイコンを貼り付けて、選択された画像を MainWindow に大きく描画します。
また良い機会なので、グループ制御でラジオボタンを操作する方法を説明しています。

  1. WinMain() で通常の Window を生成したら CreateDialog() で DialogBox も生成します。
    そして ShowWindow(),UpdateWindow() で共に表示します。
    画面には MainWindow と DialogBox が同時に表示されます。
        hDlg = CreateDialog(hInst,MAKEINTRESOURCE(IDD_DIALOG1),hWnd,(DLGPROC)MyDlgProc);
        if (hDlg == NULL)    return FALSE;
    
        ShowWindow( hWnd, nCmdShow );
        UpdateWindow( hWnd );
        ShowWindow(hDlg, SW_SHOW);
        UpdateWindow(hDlg);
        
  2. WM_CREATE: から Application の初期化を呼びます。
    BMP Object に6枚の画像を入力して描画の準備を整えます。
        case WM_CREATE:
            InitApp(hWnd);
            break;
        
        //★ Application の初期設定
        int InitApp(HWND hWnd)
        {   int i;
    
            for(i=0; i<6; i++)
            {   Bmp[i]= new BMP(hWnd);
                Bmp[i]->Load(name[i]);
            }
            return 0;
        }
        
  3. WM_PAINT: では現在選択されている画像を描画します。
    nCF[] には GetMyDlg() で6個のラジオボタンの状態が格納されています。
        case WM_PAINT:
            hdc = BeginPaint (hWnd, &ps);
            // TODO: この位置に描画用のコードを追加してください...
            for(i=0; i<5 && nCF[i]==0; i++);
            Bmp[i]->Show(hdc);
            EndPaint( hWnd, &ps );
            break;
        
  4. DialogBox の CALLBACK 関数です。
    二つのウインドウは親子関係になっていて、GetParent() は親 Window(MainWindow) を取得する関数です。
    WM_INITDIALOG で IDC_RADIO6 のラジオボタンを ON に設定しています。
    このタイミングでは hDlg にハンドルが設定されていないので注意が必要です。
    IDOK で現在のラジオボタンの状態を取得して nCF[] に格納します。
    IDCANCEL で親ウインドウに WM_CLOSE をポストしてプログラムを終了します。
        hParent = GetParent(hWnd);
        switch(msg)
        {   case WM_INITDIALOG:
                Button_SetCheck(GetDlgItem(hWnd,IDC_RADIO6),BST_CHECKED);
                return TRUE;
            case WM_COMMAND:
                switch(LOWORD(wp))
                {   case IDOK:
                        GetMyDlg();
                        InvalidateRect(hParent, NULL, TRUE); 
                        return TRUE;
                    case IDCANCEL:
                        SendMessage(hParent, WM_CLOSE, 0, 0L);
                        return TRUE;
                }
        }
        
        //★ ラジオボタンの情報を nCF[i] に設定する
        int GetMyDlg()
        {   int     i;
    
            for(i=0; i<6; i++)
                nCF[i] = Button_GetCheck(GetDlgItem(hDlg,ID[i]));
            return i;
        }
        

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