オーナードローメニューを作成する(C/C++版)
オーナードローメニューを作成するサンプルです。
サンプルの実行画面
ソースコード
[Sample18.c]
//-------------------------------------------------------------------------------------- // ■オーナードローメニューを作成する■ Sample NO.18 // //-------------------------------------------------------------------------------------- //リンクの設定 //comctl32.libをリンクに追加 //C/C++版のオーナードローメニューサンプル(ODM)にもメニューの横にグラデーションを入れる予定だったが面倒なのでやめました。 //気になる人はDelphiコーナーの特選サンプル集をご覧下さい。(Delphi3.0/3.1が必要) #include <windows.h> #include <commctrl.h> //コントロールID #define ID_ACCEL 505 #define ID_MENU 5000 #define ID_MENU1 1000 #define ID_MENU2 1001 #define ID_MENU3 1002 #define ID_MENU4 1003 #define ID_RADIO1 500 #define ID_RADIO2 501 #define ID_RADIO3 502 //オーナードローメニューアイテム構造体 struct ODMITEM { int MenuID; //メニューID int ImageIndex; //メニューのアイコンインデックス char MenuString[MAX_PATH]; //メニュー文字列 char ShortCut[30]; //ショートカットキー(アクセラレータキー) }; HIMAGELIST hImageList; //イメージリストのハンドル HFONT hFont; //フォントのハンドル struct ODMITEM _ODMITEM[4]; //オーナードローメニューのアイテム構造体 int TextHeight,TextWidth;//メニューのテキストのサイズ HWND hRadio[3]; //ラジオボタンハンドル const int ImageSize= 16 ; //イメージのサイズ //コールバックプロシージャ LRESULT CALLBACK WindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam); //------------------------------------------------------ //■関数 ScreenCenterX(ローカル) //■用途 ウインドウを中央にする為にX座標(LEFT)を算出する //■引数 // Width ...ウインドウの横幅 //------------------------------------------------------ int ScreenCenterX(int Width) { int X; X = (GetSystemMetrics(SM_CXSCREEN)- Width) / 2; if (X<0) X=0; return(X); } //------------------------------------------------------ //■関数 ScreenCenterY(ローカル) //■用途 ウインドウを中央にする為にY座標(TOP)を算出する //■引数 // Height ...ウインドウの縦幅 //------------------------------------------------------ int ScreenCenterY(int Height) { int Y; Y= (GetSystemMetrics(SM_CYSCREEN)- Height) / 2; if (Y<0) Y=0; return(Y); } //------------------------------------------------------ //■関数 CreateMainWindow(ローカル) //■用途 メインウインドウを作成する //■引数 // Width ...ウインドウの横幅 // Height ...ウインドウの縦幅 // Caption ...タイトル名 // hInstance ...インスタンスハンドル // nCmdShow ...ウインドウの表示形態 // lpfnWndProc...コールバックプロシージャ // dwstyle ...ウインドウスタイル // dwExstyle ...拡張ウインドウスタイル // MenuID ...メニューのID // hIcon ...アイコン //■戻り値 // ウインドウのハンドル //------------------------------------------------------ HWND CreateMainWindow(int Width,int Height,LPCTSTR Caption,HINSTANCE hInstance,int nCmdShow,WNDPROC lpfnWndProc, DWORD dwstyle,DWORD dwExstyle,LPCTSTR MenuID,HICON hIcon) { HWND hWnd; //メインウインドウのハンドル WNDCLASS myClass; //WNDCLASS構造体 //WNDCLASS構造体を0で初期化 ZeroMemory(&myClass,sizeof(WNDCLASS)); //--->WNDCLASS構造体の設定&ウインドウクラスの登録 //ウインドウスタイルを設定 myClass.style =CS_HREDRAW | CS_VREDRAW; //コールバックプロシージャへのポインタ myClass.lpfnWndProc = lpfnWndProc; //インスタンスハンドルを設定 myClass.hInstance =hInstance; //カーソルの設定(Windows標準リソースを使用) myClass.hCursor =LoadCursor(NULL, IDC_ARROW); //ウインドウの背景を設定(デフォルトカラー) myClass.hbrBackground =(HBRUSH)COLOR_WINDOW; //クラス名の設定(Borland Delphi風) myClass.lpszClassName ="TForm"; //アイコンの指定 myClass.hIcon =hIcon; //メニューの設定 myClass.lpszMenuName=MenuID; //ウィンドウ クラスを登録 RegisterClass(&myClass); //--->ウインドウの作成&表示 //メインウインドウの生成 hWnd = CreateWindowEx( //拡張ウインドウスタイル dwExstyle, //登録されたクラス名のアドレス "TForm", //ウインドウ名 Caption, //ウインドウスタイルを設定 dwstyle, //X座標の位置設定 ScreenCenterX(Width), //Y座標の位置設定 ScreenCenterY(Height), //横幅を設定 Width, //縦幅を設定 Height, //親ウインドウを設定 NULL, //メニューを設定 NULL, //インスタンスを識別 hInstance, //作成したウインドウに渡すデータへのポインタ NULL); //ウインドウの表示(表示方法はnCmdShowに従う) ShowWindow(hWnd, nCmdShow); return(hWnd); } //------------------------------------------------------ //■関数名 ControlCreate //■用途 ウインドウ(コントロール)を作成 //■引数 // hwndParent ...親ウインドウのハンドル // Left ...作成するウインドウの左隅のX座標 // Top ...作成するウインドウの左隅のY座標 // Width ...作成するウインドウの横幅 // Height ...作成するウインドウの縦幅 // dwExStyle ...ウインドウの拡張フラグ // dwFlag ...ウインドウの作成フラグ // Caption ...作成するウインドウのキャプション // ClassName ...作成するウインドウクラス名 // ChildID ...子ウインドウの識別子 // hInstance ...インスタンスハンドル //■戻り値 // 子ウインドウのハンドル //------------------------------------------------------ HWND CreateControlWindow(HWND hwndParent, int Left, int Top,int Width, int Height,int dwExStyle ,int dwFlag ,LPCTSTR Caption, LPCTSTR ClassName,HMENU ChildID,HINSTANCE hInstance) { return CreateWindowEx(dwExStyle,ClassName,Caption,WS_CHILD | WS_VISIBLE | dwFlag , Left, Top, Width, Height, hwndParent, ChildID, hInstance, NULL); } //--------------------------------------------------------------- //■関数 SetWindowFont //■用途 ウインドウのフォントを変更する //■引数 // hwnd ...フォントを変更するウインドウのハンドル // Height ...フォントの縦幅 // Weight ...フォントの太さ // Italic ...斜体フラグ // Underlin ...アンダーラインフラグ // StrikeOut ...打ち消し線フラグ // FontName ...フォントの名前 //--------------------------------------------------------------- HFONT SetWindowFont(HWND hwnd,int Height,int Weight,BOOL Italic,BOOL Underlin,BOOL StrikeOut, LPCTSTR FontName) { HFONT hFont; hFont= (CreateFont(-12,0,0,0,Weight,Italic,Underlin,StrikeOut,SHIFTJIS_CHARSET, OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH,FontName)); SendMessage(hwnd,WM_SETFONT,(WPARAM)hFont,TRUE); return(hFont); } //-------------------------------------------------------- //■関数 WinMain //■用途 メインの関数 //■引数 // hInstance ...現在のインスタンスのハンドル // hPrevInstance...以前のインスタンスのハンドル // pszCmdLine ...コマンド ラインのアドレス // nCmdShow ...ウィンドウの表示状態 //-------------------------------------------------------- int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { MSG msg; HACCEL hAccel; HWND hwnd; //メインウインドウを作成 hwnd= CreateMainWindow(280,230,"オーナードローメニューを作成する",hInstance,nCmdShow,(WNDPROC)WindowProc, WS_OVERLAPPEDWINDOW,WS_EX_CONTROLPARENT | WS_EX_WINDOWEDGE,MAKEINTRESOURCE(ID_MENU),LoadIcon(NULL,MAKEINTRESOURCE(IDI_APPLICATION))); //アクセラレータキーのリソースロード hAccel = LoadAccelerators(hInstance, MAKEINTRESOURCE(ID_ACCEL)); //送られてくるメッセージを翻訳してプロシージャに渡す while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(hwnd, hAccel, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return (msg.wParam); } //------------------------------------------------------ // ■関数 WindowProc // ■用途 メインウインドウに送られるメッセージを処理 // ■引数 // hwnd ...ウインドウのハンドル // uMsg ...メッセージID // wParam ...第1メッセージ パラメータ // lParam ...第2メッセージ パラメータ //------------------------------------------------------ LRESULT CALLBACK WindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam) { LPDRAWITEMSTRUCT _DrawItem =(LPDRAWITEMSTRUCT)lParam; LPMEASUREITEMSTRUCT _MeasureItem=(LPMEASUREITEMSTRUCT) lParam; int i,buf ; HBRUSH hBrush; HBITMAP hBMP; HFONT hFont; RECT Rect,IconRect,_FillRect; SIZE Size; HDC hDC; HMENU hMenu,hPopUp; POINT Point; HWND hStatic; switch (uMsg) { case WM_CREATE: //オーナードロ―メニューに変更 hMenu=GetMenu(hwnd); ModifyMenu(hMenu,ID_MENU1,MF_OWNERDRAW | MF_BYCOMMAND,ID_MENU1,NULL); ModifyMenu(hMenu,ID_MENU2,MF_OWNERDRAW | MF_BYCOMMAND,ID_MENU2,NULL); ModifyMenu(hMenu,ID_MENU3,MF_OWNERDRAW | MF_BYCOMMAND,ID_MENU3,NULL); ModifyMenu(hMenu,ID_MENU4,MF_OWNERDRAW | MF_BYCOMMAND,ID_MENU4,NULL); //構造体に情報を設定(ショートカットキーはここで設定してください。) _ODMITEM[0].MenuID =ID_MENU1; _ODMITEM[1].MenuID =ID_MENU2; _ODMITEM[2].MenuID =ID_MENU3; _ODMITEM[3].MenuID =ID_MENU4; _ODMITEM[0].ImageIndex=0; _ODMITEM[1].ImageIndex=1; _ODMITEM[2].ImageIndex=2; _ODMITEM[3].ImageIndex=-1; GetMenuString(hMenu,ID_MENU1,_ODMITEM[0].MenuString,MAX_PATH,MF_BYCOMMAND); GetMenuString(hMenu,ID_MENU2,_ODMITEM[1].MenuString,MAX_PATH,MF_BYCOMMAND); GetMenuString(hMenu,ID_MENU3,_ODMITEM[2].MenuString,MAX_PATH,MF_BYCOMMAND); GetMenuString(hMenu,ID_MENU4,_ODMITEM[3].MenuString,MAX_PATH,MF_BYCOMMAND); strcpy(_ODMITEM[0].ShortCut,"\tCtrl+N"); strcpy(_ODMITEM[1].ShortCut,"\tCtrl+O"); strcpy(_ODMITEM[2].ShortCut,"\tCtrl+S"); strcpy(_ODMITEM[3].ShortCut," "); //イメージリストを作成 hImageList= ImageList_Create(ImageSize,ImageSize,ILC_COLOR | ILC_MASK,3,0); //イメージリストにビットマップを追加 for (i=1;i<4;i++) { hBMP = LoadBitmap((HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE),(LPCTSTR)100+i); ImageList_AddMasked(hImageList, hBMP, RGB(0,255,255)); DeleteObject(hBMP); } //コントロール作成 hRadio[0]=CreateControlWindow(hwnd,10,10,250,30,WS_EX_CLIENTEDGE, BS_AUTORADIOBUTTON ,"MS-WindowStyle","BUTTON",(HMENU)ID_RADIO1,(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE)); hRadio[1]=CreateControlWindow(hwnd,10,40,250,30,WS_EX_CLIENTEDGE, BS_AUTORADIOBUTTON ,"MS-OfficeStyle","BUTTON",(HMENU)ID_RADIO2,(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE)); hRadio[2]=CreateControlWindow(hwnd,10,70,250,30,WS_EX_CLIENTEDGE, BS_AUTORADIOBUTTON ,"MS-CoolStyle","BUTTON",(HMENU)ID_RADIO3,(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE)); hStatic=CreateControlWindow(hwnd,10,140,250,30,WS_EX_CLIENTEDGE, SS_LEFT,"マウス右クリックでポップアップメニューが表示されます。","STATIC",(HMENU)0,(HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE)); SendMessage(hRadio[0],BM_SETCHECK,1,0); //フォントの変更 hFont=SetWindowFont(hwnd,-12,FW_REGULAR,FALSE,FALSE,FALSE,"MS Pゴシック"); SendMessage((HWND)hMenu,WM_SETFONT,(WPARAM)hFont,TRUE); SendMessage(hStatic,WM_SETFONT,(WPARAM)hFont,TRUE); for (i=0;i<3;i++) SendMessage(hRadio[i],WM_SETFONT,(WPARAM)hFont,TRUE); break; case WM_DRAWITEM: //メニューだったら if (_DrawItem->CtlType==ODT_MENU) { //メニューIDとインデックスを顔合わせする switch (_DrawItem->itemID) { case ID_MENU1: i=0;break; case ID_MENU2: i=1;break; case ID_MENU3: i=2;break; case ID_MENU4: i=3;break; } //MS_Window Style--------------------------------------------> if (SendMessage(hRadio[0],BM_GETCHECK,0,0)==1) { if (_DrawItem->itemState & ODS_SELECTED) { //ブラシ作成 hBrush=CreateSolidBrush(RGB(0,0,128)); //テキストのカラーを設定 SetTextColor(_DrawItem->hDC,RGB(255,255,255)); //テキストの背景色を指定 SetBkColor(_DrawItem->hDC,RGB(0,0,128)) ; } else { //ブラシ作成 hBrush=CreateSolidBrush(GetSysColor(COLOR_MENU)); //テキストのカラーを設定 SetTextColor(_DrawItem->hDC,GetSysColor(COLOR_MENUTEXT)); //テキストの背景色を指定 SetBkColor(_DrawItem->hDC,GetSysColor(COLOR_MENU)) ; } //バックグラウンドを塗りつぶす FillRect(_DrawItem->hDC,&_DrawItem->rcItem,hBrush); //ブラシ削除 DeleteObject(hBrush); CopyRect(&Rect,&_DrawItem->rcItem); Rect.left=Rect.left+20; Rect.top=Rect.top+4; //テキストを描画 DrawText(_DrawItem->hDC,_ODMITEM[i].MenuString,-1,&Rect, DT_LEFT) ; Rect.right =Rect.right-12; //ショートカットキーを描画([\t]を飛ばす) if (strcmp("\t",_ODMITEM[i].ShortCut)!=0) DrawText(_DrawItem->hDC,&_ODMITEM[i].ShortCut[1],-1,&Rect,DT_RIGHT) ; //ビットマップを描画 if (-1!=_ODMITEM[i].ImageIndex) ImageList_Draw(hImageList,_ODMITEM[i].ImageIndex,_DrawItem->hDC, 2, _DrawItem->rcItem.top+2, ILD_TRANSPARENT); break; } //MS-OfficeStyle--------------------------------------------> if (SendMessage(hRadio[1],BM_GETCHECK,0,0)==1) { //浮出しアイコンのサイズ IconRect.left=0; IconRect.top=_DrawItem->rcItem.top; IconRect.bottom=TextHeight+_DrawItem->rcItem.top; IconRect.right=ImageSize+4; //浮出しアイコンのサイズ以外の領域 _FillRect.left=ImageSize+5; _FillRect.top=_DrawItem->rcItem.top; _FillRect.bottom=_DrawItem->rcItem.bottom; _FillRect.right=_DrawItem->rcItem.right; if (_DrawItem->itemState & ODS_SELECTED) { //ブラシ作成 hBrush=CreateSolidBrush(RGB(0,0,128)); //テキストのカラーを設定 SetTextColor(_DrawItem->hDC,RGB(255,255,255)); //テキストの背景色を指定 SetBkColor(_DrawItem->hDC,RGB(0,0,128)) ; //バックグラウンドを塗りつぶす if (-1!=_ODMITEM[i].ImageIndex) FillRect(_DrawItem->hDC,&_FillRect,hBrush); else FillRect(_DrawItem->hDC,&_DrawItem->rcItem,hBrush); } else { //ブラシ作成 hBrush=CreateSolidBrush(GetSysColor(COLOR_MENU)); //テキストのカラーを設定 SetTextColor(_DrawItem->hDC,GetSysColor(COLOR_MENUTEXT)); //テキストの背景色を指定 SetBkColor(_DrawItem->hDC,GetSysColor(COLOR_MENU)) ; //バックグラウンドを塗りつぶす FillRect(_DrawItem->hDC,&_DrawItem->rcItem,hBrush); } //ブラシ削除 DeleteObject(hBrush); CopyRect(&Rect,&_DrawItem->rcItem); Rect.left=Rect.left+25; Rect.top=Rect.top+4; //テキストを描画 DrawText(_DrawItem->hDC,_ODMITEM[i].MenuString,-1,&Rect, DT_LEFT) ; Rect.right =Rect.right-12; //ショートカットキーを描画([ ]を飛ばす) if (strcmp(" ",_ODMITEM[i].ShortCut)!=0) DrawText(_DrawItem->hDC,&_ODMITEM[i].ShortCut[1],-1,&Rect,DT_RIGHT) ; //ビットマップを描画 if (-1!=_ODMITEM[i].ImageIndex) ImageList_Draw(hImageList,_ODMITEM[i].ImageIndex,_DrawItem->hDC, 2, _DrawItem->rcItem.top+2, ILD_TRANSPARENT); //もっこりさせる(^^; if ((_DrawItem->itemState & ODS_SELECTED) && (-1!=_ODMITEM[i].ImageIndex)) DrawEdge(_DrawItem->hDC,(LPRECT)&IconRect,BDR_RAISEDINNER,BF_RECT); break; } //MS-CoolStyle--------------------------------------------> if (SendMessage(hRadio[2],BM_GETCHECK,0,0)==1) { if (_DrawItem->itemState & ODS_SELECTED) { //ブラシ作成 hBrush=CreateSolidBrush(RGB(192,192,192)); //テキストのカラーを設定 SetTextColor(_DrawItem->hDC,RGB(255,255,255)); //テキストの背景色を指定 SetBkColor(_DrawItem->hDC,RGB(192,192,192)) ; //バックグラウンドを塗りつぶす FillRect(_DrawItem->hDC,&_DrawItem->rcItem,hBrush); //もっこりさせる(^^; DrawEdge(_DrawItem->hDC,(LPRECT)&_DrawItem->rcItem,BDR_RAISEDINNER,BF_RECT); } else { //ブラシ作成 hBrush=CreateSolidBrush(GetSysColor(COLOR_MENU)); //テキストのカラーを設定 SetTextColor(_DrawItem->hDC,GetSysColor(COLOR_MENUTEXT)); //テキストの背景色を指定 SetBkColor(_DrawItem->hDC,GetSysColor(COLOR_MENU)) ; //バックグラウンドを塗りつぶす FillRect(_DrawItem->hDC,&_DrawItem->rcItem,hBrush); } //ブラシ削除 DeleteObject(hBrush); CopyRect(&Rect,&_DrawItem->rcItem); Rect.left=Rect.left+20; Rect.top=Rect.top+4; //テキストを描画 DrawText(_DrawItem->hDC,_ODMITEM[i].MenuString,-1,&Rect, DT_LEFT) ; Rect.right =Rect.right-12; //ショートカットキーを描画([ ]を飛ばす) if (strcmp(" ",_ODMITEM[i].ShortCut)!=0) DrawText(_DrawItem->hDC,&_ODMITEM[i].ShortCut[1],-1,&Rect,DT_RIGHT) ; //ビットマップを描画 if (-1!=_ODMITEM[i].ImageIndex) ImageList_Draw(hImageList,_ODMITEM[i].ImageIndex,_DrawItem->hDC, 2, _DrawItem->rcItem.top+2, ILD_TRANSPARENT); break; } }//first end if break; case WM_MEASUREITEM : if (_MeasureItem->CtlType==ODT_MENU) { hDC=GetDC(hwnd); switch (_DrawItem->itemID) { case ID_MENU1: i=0;break; case ID_MENU2: i=1;break; case ID_MENU3: i=2;break; case ID_MENU4: i=3;break; } //メニューの文字数を取得(メニュー文字列&ショートカット) if (NULL!=_ODMITEM[i].ShortCut) buf=wcslen((wchar_t*)_ODMITEM[i].MenuString)+2+wcslen((wchar_t*)_ODMITEM[i].ShortCut)+2 ; else buf=wcslen((wchar_t*)_ODMITEM[i].MenuString)+2; //テキストの幅を取得 GetTextExtentPoint32(hDC,_ODMITEM[i].MenuString,buf,&Size); _MeasureItem->itemHeight=Size.cy+(2*2); if (TextWidth<Size.cx+50) { //50はイメージサイズ(16x2)と余白を足したもの _MeasureItem->itemWidth=Size.cx+50; TextWidth=Size.cx+50; } ReleaseDC(hwnd,hDC); //テキストのサイズを格納 TextHeight=_MeasureItem->itemHeight; } break; case WM_RBUTTONDOWN: //ポップアップメニュー制御 Point.x = LOWORD(lParam); Point.y = HIWORD(lParam); hPopUp = GetSubMenu(GetMenu(hwnd), 0); ClientToScreen(hwnd, &Point); TrackPopupMenu(hPopUp, TPM_LEFTALIGN, Point.x, Point.y, 0, hwnd, NULL); break; case WM_COMMAND: switch (LOWORD(wParam)) { case ID_MENU1: MessageBox(hwnd,"「新規作成」をクリック","情報",MB_OK);break; case ID_MENU2: MessageBox(hwnd,"「ファイルを開く」をクリック","情報",MB_OK);break; case ID_MENU3: MessageBox(hwnd,"「名前を付けて保存」をクリック","情報",MB_OK);break; case ID_MENU4: SendMessage(hwnd,WM_SYSCOMMAND,SC_CLOSE,0); break; } break; case WM_DESTROY: //イメージリストを破棄 ImageList_Destroy(hImageList); DeleteObject(hFont); PostQuitMessage(0); break; //その他のメッセージはWindowsに任せる default:return(DefWindowProc(hwnd, uMsg, wParam, lParam)); } return (0); }
ソースコード一式のダウンロード
capi_sample18.zip 6,329 バイト
動作環境
このサンプルは 「Windows98」及び「Microsoft Visual C++5.0」「Borland C++ Compiler 5.5」で確認しております。環境が異なる場合は正常に動作しない場合もございますのでご了承下さい。
Visual C++5.0でのコンパイル
VC5.0でサンプルをコンパイルする場合は新規プロジェクト(Win32Application)を作成後、各ファイルを追加してビルドしてください。
Borland C++ Compiler 5.5でのコンパイル
BCC5.5でサンプルをコンパイルする場合は「bcc32.exe」で*.c又は*.cppファイルをコンパイルします。リソースがある場合は「brc32.exe」で*resファイルを付与してください。
サンプルについて
このWindows APIサンプル集(C/C++版)は2000年頃にC/C++言語の学習の為に作成したものです。コードはエレガントではなく「初心者レベルのコーディング」です。仕事などの業務で利用する際にはエラー処理やメモリ解放などの再確認を必ずして下さい。
スポンサーリンク
関連記事
公開日:2015年03月19日
記事NO:00474