メニュー選択で国旗を切り替える


日本

オランダ

クウェート

VC++ で日本、オランダ、クウェートの国旗をメニュー選択で切り替えます。

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

プロジェクトの設定

  1. 新規プロジェクト(Menu)を作成して「// グローバル変数 :」の位置までスクロールして下さい。
    クウェートの国旗を描くための4角形の座標と、表示する国旗の番号を記憶する領域を定義します。
    pont[] は四角形ポリゴンの座標定義です。
    flag_no の初期値をゼロにして、0番の国旗(日本)を最初に表示します。
    ポリゴンの描画は Polyline() で三角形、四角形、五角形を描く を参照して下さい。
        // グローバル変数 :
        HINSTANCE hInst;                                // 現在のインターフェイス
        TCHAR szTitle[MAX_LOADSTRING];                  // タイトル バーのテキスト
        TCHAR szWindowClass[MAX_LOADSTRING];            // メイン ウィンドウ クラス名
        POINT   pont[] = { 10,10, 80,76, 80,142, 10,208 };
        int     flag_no= 0;
        
  2. 国旗を描画する3個の関数を定義します。
    自動的に生成される「関数の宣言」に続いて以下のソースコードを追加して下さい。
    最初に関数のプロトタイプを宣言して、続いて関数の本文を記述します。
        // このコード モジュールに含まれる関数の宣言を転送します :
        ATOM                MyRegisterClass(HINSTANCE hInstance);
        BOOL                InitInstance(HINSTANCE, int);
        LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
        LRESULT CALLBACK    About(HWND, UINT, WPARAM, LPARAM);
        void                flag0(HDC hdc);
        void                flag1(HDC hdc);
        void                flag2(HDC hdc);
    
        //日本の国旗
        void flag0(HDC hdc)
        {
            HPEN        hOldPen;
            HBRUSH      hBrush1,hBrush2,hOldBrush;
            //日本の国旗を描画するソースコードを記述します
                  :
                  :
            DeleteObject(hBrush2);
        }
    
        //オランダの国旗
        void flag1(HDC hdc)
        {
            HPEN        hOldPen;
            //オランダの国旗を描画するソースコードを記述します
                  :
                  :
            DeleteObject(hBrush3);
        }
    
        //クウェートの国旗
        void flag2(HDC hdc)
        {
            HPEN        hOldPen;
            //クウェートの国旗を描画するソースコードを記述します
                  :
                  :
            DeleteObject(hBrush3);
        }
        
  3. WndProc() にメニューを処理するコードを追加します。
        // 選択されたメニューの解析 :
        switch (wmId)
        {         :
                  :
                  :
            case IDC_FLAG0:
                flag_no= 0;
                InvalidateRect(hWnd, NULL, TRUE);
                break;
            case IDC_FLAG1:
                flag_no= 1;
                InvalidateRect(hWnd, NULL, TRUE);
                break;
            case IDC_FLAG2:
                flag_no= 2;
                InvalidateRect(hWnd, NULL, TRUE);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
        }
        break;
        
  4. WM_PAINT: に国旗を描画する関数を呼び出すコードを追加します。
        case WM_PAINT:
            hdc = BeginPaint(hWnd, &ps);
            // TODO: 描画コードをここに追加してください...
            switch (flag_no)
            {   case 0: flag0(hdc);  break;
                case 1: flag1(hdc);  break;
                case 2: flag2(hdc);  break;
            }
            EndPaint(hWnd, &ps);
            break;
        
  5. 国旗のサイズに合わせてウインドウサイズを「幅=330、高さ=270」に設定して下さい。
    また背景色をグレーに設定して下さい。
    ウインドウサイズと背景色の設定は 矩形を描画する を参照して下さい。
  6. 国旗を選択するメニューを設定します。
    1. リソースで定義された基本メニューは、次のようになっています。
              IDC_MAIN MENU 
              BEGIN
                  POPUP "ファイル(&F)"
                  BEGIN
                      MENUITEM "アプリケーションの終了(&X)",       IDM_EXIT
                  END
                  POPUP "ヘルプ(&H)"
                  BEGIN
                      MENUITEM "バージョン情報 ...(&A)",           IDM_ABOUT
                  END
              END
              
    2. Resource(リソース) タブから IDC_MAIN をダブルクリックしてメニュー編集のウインドウを表示します。
      リソースが設定されていないときは、メニューバーから「プロジェクト(P)/リソースの追加(R)/MENU/新規作成」を選びます。
      説明の画像
      ヘルプ(H) を右クリックして[新しい項目を挿入]を選びます。
      [ファイル]と[ヘルプ]の間に新しいメニューが追加されます。
    3. 新しいメニューのキャプションウインドウに「国旗選択(&S)」とタイプします。

    4. [国旗選択(&S)]の下の[ここへ入力]を右クリックしてプロパティを選びます。
      キャプションに「日本(&J)」を、ID に IDC_FLAG0 をタイプしてウインドウを閉じます。
    5. もう一度[ここへ入力]を右クリックしてプロパティを選びます。
      キャプションに「オランダ(&O)」を、ID に IDC_FLAG1 をタイプしてウインドウを閉じます。
    6. もう一度[ここへ入力]を右クリックしてプロパティを選びます。
      キャプションに「クウェート(&K)」を、ID に IDC_FLAG2 をタイプしてウインドウを閉じます。

  7. 空のプロジェクトから作成したときは、次の確認をして下さい。
    [デバッグ][デバッグなしで開始]を選択して、ビルドに続いて実行を行います。
    日本の国旗が表示されて、メニュー選択で「日本、オランダ、クウェート」の国旗に切り替わったら完成です。
    [Alt][S][K]のキーを順にタイプしてクウェートの国旗が表示されることを確認して下さい。

プログラムの説明

選択されたメニューによって flag_no を設定して InvalidateRect() を実行します。
InvalidateRect() が実行されると現在表示中の矩形領域が破棄されて、再描画のために WM_PAINT: がポストされます。
InvalidateRect() をコメントにしてプログラムを実行してみて下さい。
メニューで国旗を切り替えても表示が変わらなくなります。
その状態でウインドウを移動すると変更された国旗が描画されるでしょう。
ウインドウの移動によって WM_PAINT: がポストされたからです。
  case IDC_FLAG0:
       flag_no= 0;
       InvalidateRect(hWnd, NULL, TRUE);
       break;
   case IDC_FLAG1:
       flag_no= 1;
       InvalidateRect(hWnd, NULL, TRUE);
       break;
   case IDC_FLAG2:
       flag_no= 2;
       InvalidateRect(hWnd, NULL, TRUE);
       break;

InvalidateRect() が実行されると WM_PAINT: に制御が渡され flag_no で指示された新しい国旗を描画します。
  switch (flag_no)
  {   case 0: flag0(hdc);  break;
      case 1: flag1(hdc);  break;
      case 2: flag2(hdc);  break;
  }

コンパイラのバグ?

初期のバージョンでは MENU の設定でコンパイラのバグがあるようです。
Menu 関係でエラーが発生したときは Resource.h と Main.rc を調べて下さい。
対処の方法は「エディッタなどで直接修正」するのが最も簡明な方法です。

【発生事例】

正常な MENU の記述

Resource.h
#define IDC_INFO                        0
#define IDC_GET                         129

Main.rc
    BEGIN
        MENUITEM "画像入力(&G)",                IDC_GET
        MENUITEM "画像情報(&I)",                IDC_INFO
    END


エラーが発生した MENU の記述

  1. 二個の ID に同じ値が割り当てられています。
  2. 二個の MENU に同じ ID が割り当てられています。
Resource.h
#define IDC_GET                         0
#define IDC_INFO                        0

Main.rc
    BEGIN
        MENUITEM "画像入力(&G)",                IDC_GET
        MENUITEM "画像情報(&I)",                IDC_GET
    END

【演習】

幾つかの国旗をメニューに追加して下さい。

関数のソースコード

超初心者の方のために関数のソースコードを掲載します。 (^_^;)

//日本の国旗
void flag0(HDC hdc)
{
    HPEN        hOldPen;
    HBRUSH      hBrush1,hBrush2,hOldBrush;
    hBrush1= CreateSolidBrush(RGB(255,255,255));
    hBrush2= CreateSolidBrush(RGB(220,0,0));
    hOldPen= (HPEN)SelectObject(hdc,GetStockObject(NULL_PEN));
    hOldBrush= (HBRUSH)SelectObject(hdc,hBrush1);
    Rectangle(hdc,10,10,310,210);
    SelectObject(hdc,hBrush2); 
    Ellipse(hdc,110,60,210,160);
    SelectObject(hdc,hOldBrush);
    SelectObject(hdc,hOldPen);
    DeleteObject(hBrush1);
    DeleteObject(hBrush2);
}

//オランダの国旗
void flag1(HDC hdc)
{
    HPEN        hOldPen;
    HBRUSH      hBrush1,hBrush2,hBrush3,hOldBrush;
    hBrush1= CreateSolidBrush(RGB(255,255,255));
    hBrush2= CreateSolidBrush(RGB(220,0,0));
    hBrush3= CreateSolidBrush(RGB(0,130,200));
    hOldPen= (HPEN)SelectObject(hdc,GetStockObject(NULL_PEN));
    hOldBrush= (HBRUSH)SelectObject(hdc,hBrush2);
    Rectangle(hdc,10,10,310,76);
    SelectObject(hdc,hBrush1); 
    Rectangle(hdc,10,76,310,142);
    SelectObject(hdc,hBrush3); 
    Rectangle(hdc,10,142,310,208);
    SelectObject(hdc,hOldBrush);
    SelectObject(hdc,hOldPen);
    DeleteObject(hBrush1);
    DeleteObject(hBrush2);
    DeleteObject(hBrush3);
}

//クウェートの国旗
void flag2(HDC hdc)
{
    HPEN        hOldPen;
    HBRUSH      hBrush1,hBrush2,hBrush3,hOldBrush;
    hBrush1= CreateSolidBrush(RGB(255,255,255));
    hBrush2= CreateSolidBrush(RGB(214,0,57));
    hBrush3= CreateSolidBrush(RGB(0,140,74));
    hOldPen= (HPEN)SelectObject(hdc,GetStockObject(NULL_PEN));
    hOldBrush= (HBRUSH)SelectObject(hdc,hBrush3);
    Rectangle(hdc,10,10,310,76);
    SelectObject(hdc,hBrush1); 
    Rectangle(hdc,10,76,310,142);
    SelectObject(hdc,hBrush2); 
    Rectangle(hdc,10,142,310,208);
    SelectObject(hdc,(HBRUSH)GetStockObject(BLACK_BRUSH));
    Polygon(hdc,pont,4);
    SelectObject(hdc,hOldBrush);
    SelectObject(hdc,hOldPen);
    DeleteObject(hBrush1);
    DeleteObject(hBrush2);
    DeleteObject(hBrush3);
}

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