34章 メニューとキーボードアクセラレーター(その6)

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=shift_jis"></meta>
<title>34章 メニューとキーボードアクセラレーター(その6)
</title>
</head>

<body bgcolor="WHITE">
<font size="5">34章 メニューとキーボードアクセラレーター(その6)
</font>
<hr>
<p>
 前回は、簡単なメニューの操作の仕方を説明し、最後に、MENUITEMINFO構造体を用いる方法を提示しました。今回は、MENUITEMINFO構造体を理解して、<b><i><u>メニューの動的な作成を学びましょう</u></i></b>。
<p align="LEFT"><img src="/web/20150121054011im_/http://web.kyoto-inet.or.jp:80/people/ysskondo/from29/chap34_1.gif">
<p align="RIGHT"><img src="/web/20150121054011im_/http://web.kyoto-inet.or.jp:80/people/ysskondo/from29/chap34_2.gif">
<p align="CENTER"><a href="chap34.lzh">ダウンロード</a>
<hr>
<p>
<b>
・MENUITEMINFO構造体
</b>
<p>
<table border="1" bgcolor="#F0F0F0">
<tr><td>
<pre>
typedef struct tagMENUITEMINFO {
  UINT    cbSize; 
   UINT    fMask; 
   UINT    fType; 
   UINT    fState; 
   UINT    wID; 
   HMENU   hSubMenu; 
   HBITMAP hbmpChecked; 
   HBITMAP hbmpUnchecked; 
   DWORD   dwItemData; 
   LPTSTR  dwTypeData; 
   UINT    cch; 
} MENUITEMINFO
</pre>
</table>
<p>
 この構造体は、前章で使った<b><i><u>GetMenuItemInfo関数</u></i></b>と<b><i><u>SetMenuItemInfo関数</u></i></b>以外に、今回用いる<b><i><u>InserMenuItem関数</u></i></b>で用いられています。<br>
 この様に汎用的な構造体は、メンバ変数の数が多く、また、一度に全部利用されないのも特徴です。では、表にしてメンバ変数の意味を理解しましょう。
<p>
<table border="1">
  <tr>
       <th width="160" align="CENTER" bgcolor="#F0F0F0">メンバ変数</td>
       <th align="CENTER" bgcolor="#F0F0F0">値とその意味</td>
   </tr>
   <tr>
       <td>cbSize</td>
       <td>MENUITEMINFO構造体のサイズです。何故、この様なメンバ変数が最初にあるかと言うと、将来の拡張の為です。</td>
   </tr>
   <tr>
       <td><b>fMask</b></td>
       <td>以下、どのメンバが有効になるかを示すビットです。論理積で用いる事ができます。<br>
           <b>MIIM_TYPE</b> : ftypeメンバ変数が有効になります。<br>
           <b>MIIM_STATE</b> : fStateメンバ変数が有効になります。<br>
           <b>MIIM_ID</b> : wIDメンバ変数が有効になります。<br>
           <b>MIIM_SUBMENU</b> : hSubMenuメンバ変数が有効になります。<br>
           <b>MIIM_CHECKMARKS</b>:hbmpCheckedメンバ変数とhbmpUncheckedメンバ変数が有効になります。<br>
           <b>MIIM_DATA</b> : dwItemDataメンバ変数が有効になります。<br>
           <b>MIIM_TYPE</b> : dwTypeDataメンバ変数が有効になります。<br>
       </td>
   </tr>
   <tr>
       <td>fType</td>
       <td>
           以下のビットから選びます。論理積で組み合わせる事も可能です。<br>
           <b>MFT_BITMAP</b> : メニュー項目がビットマップになります。<br>
           <b>MFT_MENUBARBREAK</b> : サブメニューが棒線で区切られ横に並びます。<br>
           <b>MFT_MENUBREAK</b> : サブメニューが横に並びます。<br>
           <b>MFT_OWNERDRAW</b> : メニューをプログラマーが描画します。<br>
           <b>MFT_RADIOCHECK</b> : 択一式のメニューを作成します。<br>
           <b>MFT_RIGHTJUSTIFY</b> : メニューが横方向に揃えられます。<br>
           <b>MFT_SEPARATOR</b> : 区切り線が表示されます<br>
           <b>MFT_STRING</b> : 文字列が表示されます。この場合、cchメンバ変数が有効になります。
       </td>
   </tr>
   <tr>
       <td>fState</td>
       <td>
           <b>MFS_CHECKED</b> : メニュー項目の左端にチェックマークが付きます。<br>
           <b>MFS_DEFAULT</b> : 標準状態<br>
           <b>MFS_DISABLED</b> : 外見上は標準状態で、選べません。(これにはバグがあります。MF_DISABLEDで回避してください)<br>
           <b>MFS_ENABLED</b> : メニュー項目が使える状態です。<br>
           <b>MFS_GRAYED</b> : メニューが灰色になって、使えません。<br>
           <b>MFS_HILITE</b> : 初期状態で、メニューが選択された様に表示されます。<br>
           <b>MFS_UNCHECKED</b> : メニュー項目がチェックされていない状態です。<br>
           <b>MFS_UNHILITE</b> : メニューが選択されていないように見えます<br>
       </td>
   </tr>
   <tr>
       <td>wID</td>
       <td>WM_COMMADNで送るアプリケーション定義の16ビット値</td>
   </tr>
   <tr>
       <td>hSubMenu</td>
       <td>サブメニューのハンドル</td>
   </tr>
   <tr>
       <td>hbmpChecked</td>
       <td>チェックされたときに表示するビットマップのハンドル</td>
   </tr>
   <tr>
       <td>hbmpUnchecked</td>
       <td>チェックされていないときに表示するビットマップのハンドル</td>
   </tr>
   <tr>
       <td>dwItemData</td>
       <td>メニュー項目と関連付けたアプリケーション定義の値</td>
   </tr>
   <tr>
       <td>dwTypeData</td>
       <td>MTF_BITMAP、MFT_SEPARATOR、MFT_STRINGにに依存する。</td>
   </tr>
   <tr>
       <td>cch</td>
       <td>MFT_STRINGの場合、文字列の長さ</td>
   </tr>
</table>
<p>
 せっかく表にしたのですから、くどくど説明しません。重要なポイントを説明し、実際のソースコードを読む事で理解しましょう。
<p>
 MENUITEMINFO構造体で重要な意味を持つメンバ変数は、<b><i><u>fMask</u></i></b>と言っても過言では無いでしょう。この変数の状態で、以下のメンバ変数が有効になったり無効になったりします。これさえ分かれば、後は、表での説明と実際のソースコードを見れば、理解出来ると思います。
<p>
 では、実際のソースコードを見てみましょう。今回は、オーナードローという方法でもメニュー項目を実装したので、かなり大きくなっていますが、論点となる箇所は、長いだけで単純です。

<p>
<table border="1" bgcolor="#F0F0F0">
<caption align="BOTTOM">リスト34-1
<tr><td>
<pre>
/* C言語で始めるWindowsプログラミング */
/* 34章のサンプルプログラム */
/* Programmed by Y.Kondo */
/* 注:TABサイズは4で見てください */
/* このファイルでは、メインウインドウのウインド*/
/*ウプロシージャが定義されている */

#define STRICT
#include &lt;windows.h&gt;
#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include "wndproc.h"
#include "resource.h"

/*===============================================================================*/

/* このファイル内でのみ用いられる関数のプロトタイプ宣言 */
static LRESULT Wm_CreateProc(HWND,LPCREATESTRUCT);
static LRESULT Wm_DrawItem(HWND,LPDRAWITEMSTRUCT);
static LRESULT Wm_MesureItemProc(HWND,UINT,LPMEASUREITEMSTRUCT);
static LRESULT Wm_CommandProc(HWND,WORD,WORD,HWND);
static LRESULT Wm_DestroyProc(HWND);

static HMENU hMainMenu; /* メインメニュー */
static HMENU hSubMenu0; /* サブメニュー0 */
static HMENU hSubMenu1; /* サブメニュー1 */

/* メインウインドウのウインドウプロシージャ */
LRESULT CALLBACK WindowProc(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam)
{
  switch(message)
   {
       case    WM_CREATE:
           return  Wm_CreateProc(hwnd,(LPCREATESTRUCT)lparam);
       case    WM_DRAWITEM:        /*  メニューのオーナードロー    */
           return  Wm_DrawItem(hwnd,(LPDRAWITEMSTRUCT) lparam);
       case    WM_MEASUREITEM:     /*  メニューのオーナードロー    */
           return  Wm_MesureItemProc(hwnd,(UINT)wparam,(LPMEASUREITEMSTRUCT)lparam);
       case    WM_COMMAND:         /*  メニューに対する処理    */
           return  Wm_CommandProc(hwnd,HIWORD(wparam),LOWORD(wparam),(HWND)lparam);
       case    WM_DESTROY:         /*  ウインドウの破壊後処理  */
           return  Wm_DestroyProc(hwnd);
   }
   return  DefWindowProc(hwnd,message,wparam,lparam);
}
<b>
static LRESULT Wm_CreateProc(HWND hwnd,LPCREATESTRUCT cs)
{
  MENUITEMINFO    MenuItemInfo;

  /*  空のメニューを作成する  */
   hMainMenu=CreateMenu();
   hSubMenu0=CreatePopupMenu();
   hSubMenu1=CreatePopupMenu();

  /*  メインメニューを作る    */
   ZeroMemory(&MenuItemInfo;,sizeof(MENUITEMINFO));
   MenuItemInfo.cbSize=sizeof(MENUITEMINFO);
   MenuItemInfo.fMask=MIIM_TYPE|MIIM_SUBMENU;
   MenuItemInfo.fType=MFT_STRING;;
   MenuItemInfo.hSubMenu=hSubMenu0;
   MenuItemInfo.dwTypeData="サブメニュー0";
   MenuItemInfo.cch=strlen(MenuItemInfo.dwTypeData);
   InsertMenuItem(hMainMenu,0,TRUE,&MenuItemInfo;);

  ZeroMemory(&MenuItemInfo;,sizeof(MENUITEMINFO));
   MenuItemInfo.cbSize=sizeof(MENUITEMINFO);
   MenuItemInfo.fMask=MIIM_TYPE|MIIM_SUBMENU;
   MenuItemInfo.fType=MFT_STRING;
   MenuItemInfo.hSubMenu=hSubMenu1;
   MenuItemInfo.dwTypeData="サブメニュー1";
   MenuItemInfo.cch=strlen(MenuItemInfo.dwTypeData);
   InsertMenuItem(hMainMenu,1,TRUE,&MenuItemInfo;);

  /*  サブメニュー0を作る    (普通の文字)*/
   ZeroMemory(&MenuItemInfo;,sizeof(MENUITEMINFO));
   MenuItemInfo.cbSize=sizeof(MENUITEMINFO);
   MenuItemInfo.fMask=MIIM_TYPE|MIIM_STATE|MIIM_ID;
   MenuItemInfo.fType=MFT_STRING;
   MenuItemInfo.fState=MFS_ENABLED;
   MenuItemInfo.wID=1000;                      /*  1000    */
   MenuItemInfo.dwTypeData="普通の文字";
   MenuItemInfo.cch=strlen(MenuItemInfo.dwTypeData);
   InsertMenuItem(hSubMenu0,0,TRUE,&MenuItemInfo;);
   
   /*  サブメニュー0を作る    (チェックマーク付き)*/
   ZeroMemory(&MenuItemInfo;,sizeof(MENUITEMINFO));
   MenuItemInfo.cbSize=sizeof(MENUITEMINFO);
   MenuItemInfo.fMask=MIIM_TYPE|MIIM_STATE|MIIM_ID;
   MenuItemInfo.fType=MFT_STRING;
   MenuItemInfo.fState=MFS_ENABLED|MFS_CHECKED;
   MenuItemInfo.wID=1001;                      /*  1001    */
   MenuItemInfo.dwTypeData="普通の文字にチェックマーク付き";
   MenuItemInfo.cch=strlen(MenuItemInfo.dwTypeData);
   InsertMenuItem(hSubMenu0,1,TRUE,&MenuItemInfo;);

  /*  サブメニュー0を作る    (アプリケーション定義のチェックマーク)*/
   ZeroMemory(&MenuItemInfo;,sizeof(MENUITEMINFO));
   MenuItemInfo.cbSize=sizeof(MENUITEMINFO);
   MenuItemInfo.fMask=MIIM_TYPE|MIIM_STATE|MIIM_ID|MIIM_CHECKMARKS;
   MenuItemInfo.fType=MFT_STRING;
   MenuItemInfo.fState=MFS_ENABLED|MFS_CHECKED;
   MenuItemInfo.wID=1002;                      /*  1002    */
   MenuItemInfo.dwTypeData="普通の文字にアプリケーション定義のチェックマーク付き";
   MenuItemInfo.hbmpChecked=LoadBitmap(cs-&gt;hInstance,MAKEINTRESOURCE(IDB_BITMAP1));
   MenuItemInfo.cch=strlen(MenuItemInfo.dwTypeData);
   InsertMenuItem(hSubMenu0,2,TRUE,&MenuItemInfo;);

  /*  サブメニュー0を作る    (セパレーター)    */
   ZeroMemory(&MenuItemInfo;,sizeof(MENUITEMINFO));
   MenuItemInfo.cbSize=sizeof(MENUITEMINFO);
   MenuItemInfo.fMask=MIIM_TYPE|MIIM_STATE;
   MenuItemInfo.fType=MFT_SEPARATOR;
   MenuItemInfo.fState=MFS_GRAYED;
   InsertMenuItem(hSubMenu0,3,TRUE,&MenuItemInfo;);

  /*  サブメニュー0を作る    (アプリケーション定義ビットマップ)*/
   ZeroMemory(&MenuItemInfo;,sizeof(MENUITEMINFO));
   MenuItemInfo.cbSize=sizeof(MENUITEMINFO);
   MenuItemInfo.fMask=MIIM_TYPE|MIIM_STATE|MIIM_ID;
   MenuItemInfo.fType=MFT_BITMAP;
   MenuItemInfo.fState=MFS_ENABLED;
   MenuItemInfo.wID=1003;                  /*  1003    */
   MenuItemInfo.dwTypeData=LoadBitmap(cs-&gt;hInstance,MAKEINTRESOURCE(IDB_BITMAP2));
   InsertMenuItem(hSubMenu0,4,TRUE,&MenuItemInfo;);

  /*  サブメニュー0を作る    (セパレーター)    */
   ZeroMemory(&MenuItemInfo;,sizeof(MENUITEMINFO));
   MenuItemInfo.cbSize=sizeof(MENUITEMINFO);
   MenuItemInfo.fMask=MIIM_TYPE|MIIM_STATE;
   MenuItemInfo.fType=MFT_SEPARATOR;
   MenuItemInfo.fState=MFS_GRAYED;
   InsertMenuItem(hSubMenu0,5,TRUE,&MenuItemInfo;);

  /*  サブメニュー0を作る    (オーナードロー項目)*/
   ZeroMemory(&MenuItemInfo;,sizeof(MENUITEMINFO));
   MenuItemInfo.cbSize=sizeof(MENUITEMINFO);
   MenuItemInfo.fMask=MIIM_TYPE|MIIM_STATE|MIIM_ID;
   MenuItemInfo.fType=MFT_OWNERDRAW;
   MenuItemInfo.fState=MFS_ENABLED;
   MenuItemInfo.wID=1004;                  /*  1004    */
   InsertMenuItem(hSubMenu0,6,TRUE,&MenuItemInfo;);

  /*  サブメニュー0を作る    (セパレーター)    */
   ZeroMemory(&MenuItemInfo;,sizeof(MENUITEMINFO));
   MenuItemInfo.cbSize=sizeof(MENUITEMINFO);
   MenuItemInfo.fMask=MIIM_TYPE|MIIM_STATE;
   MenuItemInfo.fType=MFT_SEPARATOR;
   MenuItemInfo.fState=MFS_GRAYED;
   InsertMenuItem(hSubMenu0,7,TRUE,&MenuItemInfo;);

  /*  サブメニュー0を作る    (オーナードロー項目をチェックされた状態にする)*/
   ZeroMemory(&MenuItemInfo;,sizeof(MENUITEMINFO));
   MenuItemInfo.cbSize=sizeof(MENUITEMINFO);
   MenuItemInfo.fMask=MIIM_TYPE|MIIM_STATE|MIIM_ID;
   MenuItemInfo.fType=MFT_STRING;
   MenuItemInfo.fState=MFS_ENABLED;
   MenuItemInfo.wID=1005;                  /*  1005    */
   MenuItemInfo.dwTypeData="オーナードローメニュー項目をチェックされた状態にする";
   MenuItemInfo.cch=strlen(MenuItemInfo.dwTypeData);
   InsertMenuItem(hSubMenu0,8,TRUE,&MenuItemInfo;);

  /*  サブメニュー0を作る    (オーナードロー項目を灰色にする)*/
   ZeroMemory(&MenuItemInfo;,sizeof(MENUITEMINFO));
   MenuItemInfo.cbSize=sizeof(MENUITEMINFO);
   MenuItemInfo.fMask=MIIM_TYPE|MIIM_STATE|MIIM_ID;
   MenuItemInfo.fType=MFT_STRING;
   MenuItemInfo.fState=MFS_ENABLED;
   MenuItemInfo.wID=1006;                  /*  1006    */
   MenuItemInfo.dwTypeData="オーナードローメニュー項目を灰色状態にする";
   MenuItemInfo.cch=strlen(MenuItemInfo.dwTypeData);
   InsertMenuItem(hSubMenu0,9,TRUE,&MenuItemInfo;);

  /*  サブメニュー0を作る    (オーナードロー項目を使えない状態にする)*/
   ZeroMemory(&MenuItemInfo;,sizeof(MENUITEMINFO));
   MenuItemInfo.cbSize=sizeof(MENUITEMINFO);
   MenuItemInfo.fMask=MIIM_TYPE|MIIM_STATE|MIIM_ID;
   MenuItemInfo.fType=MFT_STRING;
   MenuItemInfo.fState=MFS_ENABLED;
   MenuItemInfo.wID=1007;                  /*  1007    */
   MenuItemInfo.dwTypeData="オーナードローメニュー項目を使えない状態にする";
   MenuItemInfo.cch=strlen(MenuItemInfo.dwTypeData);
   InsertMenuItem(hSubMenu0,10,TRUE,&MenuItemInfo;);

  /*  サブメニュー0を作る    (オーナードロー項目を元に戻す)*/
   ZeroMemory(&MenuItemInfo;,sizeof(MENUITEMINFO));
   MenuItemInfo.cbSize=sizeof(MENUITEMINFO);
   MenuItemInfo.fMask=MIIM_TYPE|MIIM_STATE|MIIM_ID;
   MenuItemInfo.fType=MFT_STRING;
   MenuItemInfo.fState=MFS_ENABLED;
   MenuItemInfo.wID=1008;                  /*  1008    */
   MenuItemInfo.dwTypeData="オーナードローメニュー項目を元に戻す";
   MenuItemInfo.cch=strlen(MenuItemInfo.dwTypeData);
   InsertMenuItem(hSubMenu0,11,TRUE,&MenuItemInfo;);

  /*  サブメニュー1を作る    (普通の文字)*/
   ZeroMemory(&MenuItemInfo;,sizeof(MENUITEMINFO));
   MenuItemInfo.cbSize=sizeof(MENUITEMINFO);
   MenuItemInfo.fMask=MIIM_TYPE|MIIM_STATE|MIIM_ID;
   MenuItemInfo.fType=MFT_STRING|MFT_RADIOCHECK;
   MenuItemInfo.fState=MFS_ENABLED|MFS_CHECKED;
   MenuItemInfo.wID=2000;                      /*  2000    */
   MenuItemInfo.dwTypeData="ラジオチェック項目1";
   MenuItemInfo.cch=strlen(MenuItemInfo.dwTypeData);
   InsertMenuItem(hSubMenu1,0,TRUE,&MenuItemInfo;);

  /*  サブメニュー1を作る    (普通の文字)*/
   ZeroMemory(&MenuItemInfo;,sizeof(MENUITEMINFO));
   MenuItemInfo.cbSize=sizeof(MENUITEMINFO);
   MenuItemInfo.fMask=MIIM_TYPE|MIIM_STATE|MIIM_ID;
   MenuItemInfo.fType=MFT_STRING|MFT_RADIOCHECK;
   MenuItemInfo.fState=MFS_ENABLED;
   MenuItemInfo.wID=2001;                      /*  2001    */
   MenuItemInfo.dwTypeData="ラジオチェック項目2";
   MenuItemInfo.cch=strlen(MenuItemInfo.dwTypeData);
   InsertMenuItem(hSubMenu1,1,TRUE,&MenuItemInfo;);

  /*  サブメニュー1を作る    (普通の文字)*/
   ZeroMemory(&MenuItemInfo;,sizeof(MENUITEMINFO));
   MenuItemInfo.cbSize=sizeof(MENUITEMINFO);
   MenuItemInfo.fMask=MIIM_TYPE|MIIM_STATE|MIIM_ID;
   MenuItemInfo.fType=MFT_STRING|MFT_RADIOCHECK;
   MenuItemInfo.fState=MFS_ENABLED;
   MenuItemInfo.wID=2002;                      /*  2002    */
   MenuItemInfo.dwTypeData="ラジオチェック項目3";
   MenuItemInfo.cch=strlen(MenuItemInfo.dwTypeData);
   InsertMenuItem(hSubMenu1,2,TRUE,&MenuItemInfo;);

  /*  ウインドウとメニューを関連付ける    */
   SetMenu(hwnd,hMainMenu);

  return  0;
}</b>
static LRESULT Wm_DrawItem(HWND hwnd,LPDRAWITEMSTRUCT ds)
{
  static  BOOL    InFlag=TRUE;
   char    *Message[]={"〆 チェックされた状態",
                       "  灰色状態",
                       "  使えない状態",
                       "  選択されています",
                       "  オーナードロー",
                       "                     "};    /*  消去用  */
   if(ds-&gt;CtlType!=ODT_MENU)
       return  FALSE;
   ds-&gt;itemID=1004;
   ds-&gt;hwndItem=GetMenu(hwnd);

  switch(ds-&gt;itemAction)
   {
       case    ODA_SELECT:     /*  メニュー項目が選択されたり、選択を解除された場合、呼ばれる  */
           if(InFlag)
           {
               TextOut(ds-&gt;hDC,ds-&gt;rcItem.left,ds-&gt;rcItem.top,Message[5],strlen(Message[5]));
               TextOut(ds-&gt;hDC,ds-&gt;rcItem.left,ds-&gt;rcItem.top,Message[3],strlen(Message[3]));
           }
           else
           {
               if(ds-&gt;itemState&ODS;_CHECKED)
               {
                   TextOut(ds-&gt;hDC,ds-&gt;rcItem.left,ds-&gt;rcItem.top,Message[5],strlen(Message[5]));
                   TextOut(ds-&gt;hDC,ds-&gt;rcItem.left,ds-&gt;rcItem.top,Message[0],strlen(Message[0]));
               }
               else if(ds-&gt;itemState&ODS;_GRAYED)
               {
                   TextOut(ds-&gt;hDC,ds-&gt;rcItem.left,ds-&gt;rcItem.top,Message[5],strlen(Message[5]));
                   TextOut(ds-&gt;hDC,ds-&gt;rcItem.left,ds-&gt;rcItem.top,Message[1],strlen(Message[1]));
               }
               else if(ds-&gt;itemState&ODS;_DISABLED)
               {
                   TextOut(ds-&gt;hDC,ds-&gt;rcItem.left,ds-&gt;rcItem.top,Message[5],strlen(Message[5]));
                   TextOut(ds-&gt;hDC,ds-&gt;rcItem.left,ds-&gt;rcItem.top,Message[2],strlen(Message[2]));
               }
               else if(ds-&gt;itemState&ODS;_SELECTED)
               {
                   TextOut(ds-&gt;hDC,ds-&gt;rcItem.left,ds-&gt;rcItem.top,Message[5],strlen(Message[5]));
                   TextOut(ds-&gt;hDC,ds-&gt;rcItem.left,ds-&gt;rcItem.top,Message[3],strlen(Message[3]));
               }
               else
               {
                   TextOut(ds-&gt;hDC,ds-&gt;rcItem.left,ds-&gt;rcItem.top,Message[5],strlen(Message[5]));
                   TextOut(ds-&gt;hDC,ds-&gt;rcItem.left,ds-&gt;rcItem.top,Message[4],strlen(Message[4]));
               }
           }
           InFlag=!InFlag;
           break;
       case    ODA_DRAWENTIRE: /*  ドロップダウンメニューが描画されるときに呼ばれる    */
           if(ds-&gt;itemState&ODS;_CHECKED)
           {
               TextOut(ds-&gt;hDC,ds-&gt;rcItem.left,ds-&gt;rcItem.top,Message[5],strlen(Message[5]));
               TextOut(ds-&gt;hDC,ds-&gt;rcItem.left,ds-&gt;rcItem.top,Message[0],strlen(Message[0]));
           }
           else if(ds-&gt;itemState&ODS;_GRAYED)
           {
               TextOut(ds-&gt;hDC,ds-&gt;rcItem.left,ds-&gt;rcItem.top,Message[5],strlen(Message[5]));
               TextOut(ds-&gt;hDC,ds-&gt;rcItem.left,ds-&gt;rcItem.top,Message[1],strlen(Message[1]));
           }
           else if(ds-&gt;itemState&ODS;_DISABLED)
           {
               TextOut(ds-&gt;hDC,ds-&gt;rcItem.left,ds-&gt;rcItem.top,Message[5],strlen(Message[5]));
               TextOut(ds-&gt;hDC,ds-&gt;rcItem.left,ds-&gt;rcItem.top,Message[2],strlen(Message[2]));
           }
           else if(ds-&gt;itemState&ODS;_SELECTED)
           {
               TextOut(ds-&gt;hDC,ds-&gt;rcItem.left,ds-&gt;rcItem.top,Message[5],strlen(Message[5]));
               TextOut(ds-&gt;hDC,ds-&gt;rcItem.left,ds-&gt;rcItem.top,Message[3],strlen(Message[3]));
           }
           else
           {
               TextOut(ds-&gt;hDC,ds-&gt;rcItem.left,ds-&gt;rcItem.top,Message[5],strlen(Message[5]));
               TextOut(ds-&gt;hDC,ds-&gt;rcItem.left,ds-&gt;rcItem.top,Message[4],strlen(Message[4]));
           }
           InFlag=TRUE;    /*  選択されて終わった場合  */
           break;
   }
   return  TRUE;
}
static LRESULT Wm_MesureItemProc(HWND hwnd,UINT idCtl,LPMEASUREITEMSTRUCT lpmis)
{
  if(lpmis-&gt;CtlType!=ODT_MENU)
       return  FALSE;
   lpmis-&gt;itemID=1004;
   lpmis-&gt;itemWidth=110;
   lpmis-&gt;itemHeight=13;
   return  TRUE;
}
static LRESULT Wm_CommandProc(HWND hwnd,WORD wNotifyCode,WORD wID,HWND hwndCtl)
{

  MENUITEMINFO    MenuItemInfo;
   switch(wID)
   {
       case    1000:
           MessageBox(hwnd,"普通の文字","メッセージ",MB_OK);
           break;
       case    1001:
           MessageBox(hwnd,"普通の文字にチェックマーク付き","メッセージ",MB_OK);
           break;
       case    1002:
           MessageBox(hwnd,"普通の文字にアプリケーション定義のチェックマーク付き","メッセージ",MB_OK);
           break;
       case    1003:
           MessageBox(hwnd,"ビットマップメニュー","メッセージ",MB_OK);
           break;
       case    1004:
           MessageBox(hwnd,"オーナードローメニュー","メッセージ",MB_OK);
           break;
       case    1005:
           EnableMenuItem(GetMenu(hwnd),1004,MF_BYCOMMAND|MF_ENABLED);
           CheckMenuItem(GetMenu(hwnd),1004,MF_BYCOMMAND|MF_CHECKED);
           MessageBox(hwnd,"オーナードローメニューはチェックされました","メッセージ",MB_OK);
           break;
       case    1006:
           CheckMenuItem(GetMenu(hwnd),1004,MF_BYCOMMAND|MF_UNCHECKED);
           EnableMenuItem(GetMenu(hwnd),1004,MF_BYCOMMAND|MF_ENABLED);
           EnableMenuItem(GetMenu(hwnd),1004,MF_BYCOMMAND|MF_GRAYED);
           MessageBox(hwnd,"オーナードローメニューは灰色で使用不可になりました","メッセージ",MB_OK);
           break;
       case    1007:
           CheckMenuItem(GetMenu(hwnd),1004,MF_BYCOMMAND|MF_UNCHECKED);
           EnableMenuItem(GetMenu(hwnd),1004,MF_BYCOMMAND|MF_ENABLED);
           EnableMenuItem(GetMenu(hwnd),1004,MF_BYCOMMAND|MF_DISABLED);
           MessageBox(hwnd,"オーナードローメニューは使用不可になりました","メッセージ",MB_OK);
           break;
       case    1008:
           CheckMenuItem(GetMenu(hwnd),1004,MF_BYCOMMAND|MF_UNCHECKED);
           EnableMenuItem(GetMenu(hwnd),1004,MF_BYCOMMAND|MF_ENABLED);
           MessageBox(hwnd,"オーナードローメニューは元に戻りました","メッセージ",MB_OK);
           break;
       case    2000:
           CheckMenuRadioItem(GetMenu(hwnd),2000,2002,2000,MF_BYCOMMAND);
           break;
       case    2001:
           CheckMenuRadioItem(GetMenu(hwnd),2000,2002,2001,MF_BYCOMMAND);
           break;
       case    2002:
           CheckMenuRadioItem(GetMenu(hwnd),2000,2003,2000,MF_BYCOMMAND);
           break;
   }
   return  0;
}<b>
static LRESULT Wm_DestroyProc(HWND hwnd)
{
  /*  ここでメニューを破棄する    */
   DestroyMenu(hSubMenu0);
   DestroyMenu(hSubMenu1);
   DestroyMenu(hMainMenu);
   PostQuitMessage(0);
   return  0;
}</b>
</pre>
</table>
<p>
<b>
・動的なメニューの作成方法の概略
</b>
<p>
 動的にメニューを作成する場合、前章の二つ目の方法でのメニューのイメージで作成する必要があります。つまり、メニューの位置情報を元に変更を加える場合のイメージです。<br>
 まず、幹となるメニューを作成し、これにサブメニューという感じでメニューを作成し、より幹に近いメニューに加えていくのです。<br>
 個々のメニュー項目の作成とのメニューのTree構造の作成の順序は、特に問われません。今回は、先に、メニューのTree構造を作成し、個々の枝葉となるメニュー項目を作成しました。
<p>
<b>
・動的なメニューの破壊の概略
</b>
<p>
 動的に作成したメニューを破壊する場合、枝葉の抹消から破壊していきます。
<hr>
<p>
 メニューの動的な作成や破壊に関する関数群の説明をします。
<p>
<b>
・CreateMenu関数
</b>
<p>
 幹となる空のメニューを作成します。引数は無し。メニューハンドルを返します。メニューの作成に失敗した場合、NULLを返します。
<p>
<b>
・CreatePopupMenu関数
</b>
<p>
 枝となる空のメニューを作成します。これ以外は、CreateMenu関数と同じです。また、マウス右クリックでおなじみのフローティングポップアップメニューを作成する場合にも使います。
<p>
<b>
・InsertMenuItem関数
</b>
<p>
 これで、幹となるメニューと枝となるメニューを関連付けたり、実際のメニュー項目を作成します。<br>
 第1引数はメニューハンドル。第2引数はメニュー項目を挿入する位置。第3項目は第2引数の意味を区別します。第3引数がFALSEなら、第2引数の意味はメニュー項目の識別子。第3引数がTRUEなら、第2引数の意味は、メニューハンドル内での絶対的な位置です。第4引数はMENUITEMINFO構造体型の変数のポインタ。この関数が具体的にどの様な動作をするかは、これで決まります。成功するとTRUEを返し、失敗するとFALSEを返します。
<p>
<b>
・SetMenu関数
</b>
<p>
 メニューをウインドウに関連付ける関数です。第1引数はメニューを付けるウインドウのウインドウハンドル。第2引数はウインドウに関連付けるメニューのメニューハンドルです。成功するとTRUEを返し、失敗するとFALSEを返します。
<p>
<b>
・DestroyMenu関数
</b>
<p>
 メニューを破壊する関数です。引数に破壊するメニューハンドルを取ります。破壊に成功した場合TRUEを返し、失敗した場合FALSEを返します。
<hr>
<p>
 サブメニュー2について
<p>
 今回のサンプルの「サブメニュー2」は、ラジオチェックと言われるメニュー項目で、ボタンコントロールのラジオボタンの様に排他的にメニュー項目にチェックを付けるものです。<br>
 実装の上で、重要な関数は、<b><i><u>CheckMenuRadioItem関数</u></i></b>です。
<p>
<b>
・CheckMenuRadioItem関数
</b>
<p>
 排他的にメニュー項目にチェックを付ける関数です。第1引数はメニューハンドル。第2引数から第4引数は、第5引数によって意味が変ります。<br>
 第5引数がMF_BYCOMMANDの場合には、第2引数から第4引数はメニュー項目の識別子。第5引数がMF_BYPOSITIONの場合には、位置情報になります。<br>
 従って、第5引数がMF_BYCOMMANDの場合は、第1引数のメニューハンドルは幹となるメニューのメニューハンドル。第5引数がMF_BYPOSITIONの場合には、サブメニューのメニューハンドルになります。<br>
 第2引数は、排他的なメニュー項目の最初の識別子か位置情報。第3引数は、排他的なメニュー項目の最後の識別子か位置情報。第4引数は、チェックを入れる識別子か位置情報です。<br>
 成功するとTRUEを返し、失敗するとFALSEを返します。
<hr>
<p>
 今回は、メニューの動的な作成の方法について学びました。<br>
 サンプルプログラムでは、メニューのオーナードローも行っています。しかし、まだGDI(グラフィック・デバイス・インターフェース)について説明していませんので、特に言及しませんでした。まぁ、こんな事も出来るんだと理解して頂ければ、十分と思います。
<p>
 次回は、フローティングポップアップメニューについて説明します。
<p>
 では、お楽しみに。
<p align="RIGHT">
2003年1月6日<br>
<hr>
<p align="RIGHT">
<a href="/web/20150121054011/http://web.kyoto-inet.or.jp:80/people/ysskondo/index.html">目次</a><br>
<hr>
<p align="RIGHT">
著作権者:近藤妥
</body>
</html>

  • 最終更新:2018-03-11 05:30:11

このWIKIを編集するにはパスワード入力が必要です

認証パスワード