分享

VC API之菜单函数

 昵称3972135 2011-01-09
1.CreateMenu(VOID)
函数功能:该函数创建一个菜单。此菜单最初是空的,但可用函数InserMenultem,AppendMenu,和lnsertMenu来填入菜单项。
  函数原型:HMENU CreateMenu(VOID)
  参数:无。
  返回值:如果函数调用成功,返回值是新创建菜单的句柄。如果函数调用失败,返回值是NULL。若想获得更多的错误信息,请调用GetLastError函数。
  备注:与被分配给一个窗日的菜单相联系的资源会被自动释放。如果此菜单未被分配给一个窗口,应用程序必须在关闭之前释放与菜单相连的资源。应用程序通过调用函数DestroyMenu来释放菜单资源。
2.HMENU CreatePopupMenu(VOID)
函数功能:该函数创建一个下拉式菜单、子菜单或快捷菜单。此菜单最初是空的,但可用函数InsertMenultem来插入或追加菜单项。也可用函数InsertMenu来插人菜单项,用AppendMenu来追加菜单项。
  函数原型:HMENU CreatePopupMenu(VOID)
  参数:无。
  返回值:如果函数调用成功,返回值是新创建菜单的句柄。如果函数调用失败,返回值是NULL。若想获得更多的错误信息,请调用GetLastError函数。
  备注:一个应用程序可增加新菜单到已存在的菜单上,或者可以调用函数TrackPopupMenuEx或TrackPopupMenu来显示快捷菜单。与被分配给一个窗口的菜单相联系的资源会被自动释放。如果此菜单未被分配给一个窗口,应用程序必须在关闭之前释放与菜单相连的资源。应用程序通过调用函数DestroyMenu来释放菜单资源。Windows95环境下,系统可支持最多16,364个菜单句柄。
3.BOOL AppendMenu(hMenu hMenu,UINT uFlags,UINT uIDNewltem,LPCTSTR lpNewltem)
函数功能:该函数在指定的菜单条、下拉式菜单、子菜单或快捷菜单的末尾追加一个新菜单项。此函数可指定菜单项的内容、外观和性能。函数AppendMenu己被lnsertMenultem取代。但如果不需要lnsertMenultem的扩展特性,仍可使用AppendMenu。
  函数原型:BOOL AppendMenu(hMenu hMenu,UINT uFlags,UINT uIDNewltem,LPCTSTR lpNewltem);
  参数:
  hMenu:将被修改的菜单条、下拉式菜单、子菜单、或快捷菜单的句柄。
  UFlags:控制新菜单项的外观和性能的标志。此参数可以是备注里所列值的组合。
  UIDNewltem:指定新菜单项的标识符,或者当uFlags设置为MF_POPUP时,表示下拉式菜单或子菜单的句柄。
  LpNewltem:指定新菜单项的内容。此参数的含义取决于参数uFlags是否包含MF_BITMAP, MF_OWNERDRAW或MF_STRING标志,如下所示:
  MF_BITMAP:含有位图句柄。MF_STRING:以`\O’结束的字符串的指针。
  MF_OWNERDRAW:含有被应用程序应用的32位值,可以保留与菜单项有关的附加数据。当菜单被创建或其外观被修改时,此值在消息WM_MEASURE或WM_DRAWITEM的参数IParam指向的结构,成员itemData里。
  返回值:如果函数调用成功,返回非零值;如果函数调用失败,返回值是零。若想获得更多的错误信息,请调用GetLastError函数。
  备注:一旦菜单被修改,无论它是否在显示窗口里,应用程序必须调用函数DrawMenuBar。
下列标志可被设置在参数uFlags里:
  MF_BITMAP:将一个位图用作菜单项。参数lpNewltem里含有该位图的句柄。
  MF_CHECKED:在菜单项旁边放置一个选取标记。如果应用程序提供一个选取标记,位图(参见SetMenultemBitmaps),则将选取标记位图放置在菜单项旁边。
  MF_DISABLED:使菜单项无效,使该项不能被选择,但不使菜单项变灰。
  MF_ENABLED:使菜单项有效,使该项能被选择,并使其从变灰的状态恢复。
  MF_GRAYED:使菜单项无效并变灰,使其不能被选择。
  MF_MENUBARBREAK:对菜单条的功能同MF_MENUBREAK标志。对下拉式菜单、子菜单或快捷菜单,新列和旧列被垂直线分开。
  MF_MENUBREAK:将菜单项放置于新行(对菜单条),或新列(对下拉式菜单、子菜单或快捷菜单)且无分割列。
  MF_OWNERDRAW:指定该菜单项为自绘制菜单项。菜单第一次显示前,拥有菜单的窗口接收一个WM_MEASUREITEM消息来得到菜单项的宽和高。然后,只要菜单项被修改,都将发送WM_DRAWITEM消息给菜单拥有者的窗口程序。
  MF_POPUP:指定菜单打开一个下拉式菜单或子菜单。参数uIDNewltem下拉式菜单或子菜单的句柄。此标志用来给菜单条、打开一个下拉式菜单或于菜单的菜单项、子菜单或快捷菜单加一个名字。
  MF_SEPARATOR:画一条水平区分线。此标志只被下拉式菜单、子菜单或快捷菜单使用。此区分线不能被变灰、无效或加亮。参数IpNewltem和uIDNewltem无用。
  MF_STRING:指定菜单项是一个正文字符串;参数lpNewltem指向该字符串。
  MF_UNCHECKED:不放置选取标记在菜单项旁边(缺省)。如果应用程序提供一个选取标记位图(参见SetMenultemBitmaps),则将选取标记位图放置在菜单项旁边。
  下列标志组不能被一起使用:
  MF_DISABLED,MF_ENABLED和MF_GRAYED;MF_BITMAP,MF_STRING和MF_OWNERDRAW
  MF_MENUBARBREAK和MF_MENUBREAK;MF_CHECKED和MF_UNCHECKED
  Windows CE环境下,不支持参数fuFlags使用下列标志:
  MF_BITMAP;MF_DOSABLE;MF_GRAYED
  MF_GRAYED可用来代替MF_DISABLED和MFS_GRAYED。
  Windows CE 1.0不支持层叠式菜单。在使用Windows CE 1.0时,不能将一个MF_POPUP菜单插入到另一个下拉式菜单中。Window CE 1.0不支持下列标志:
  MF_POPUP;MF_MENUBREAK;MF_MENUBARBREAK
4.BOOL WINAPI InsertMenuItem(HMENU hMenu,UINT uItem,BOOL fByPosition,LPMENUITEMINFO lpmii);
 用一个MENUITEMINFO结构指定的特征插入一个新菜单条目
  [参数表]
  hMenu ---------- Long,菜单的句柄
  un ------------- Long,菜单条目的菜单ID。新条目会插入由这个参数指定的项目之前
  bool ----------- Boolean,如un指定的是条目的位置,就为TRUE,如指定的是菜单ID,就为FALSE
  lpcMenuItemInfo - MENUITEMINFO,用于设置指定菜单条目的特征
  [返回值]
  Long,TRUE(非零)表示成功,否则返回零。会设置GetLastError
5.BOOL DrawMenuBar(HWND hWnd)
函数功能:该函数重画指定菜单的菜单条。如果系统创建窗口以后菜单条被修改,则必须调用此函数来画修改了的菜单条。
  函数原型:BOOL DrawMenuBar(HWND hWnd);
  参数:
  hWnd:其菜单条需要被重画的窗口的句柄。
  返回值:如果函数调用成功,返回非零值:如果函数调用失败,返回值是零。若想获得更多的错误信息,请调用GetLastError函数。
HMENU  hMenu,hPopupMenu;
HMENU hOldMenu;
MENUITEMINFO mi;
char szExit[16],szAbout[16];
sprintf(szExit,"%s","&Exit11");
sprintf(szAbout,"%s","&About11");
//设置一个菜单项的具体内容
mi.cbSize=sizeof(MENUITEMINFO);  //MENUITEMINFO类型变量的大小
mi.fMask=MIIM_STATE|MIIM_TYPE; //fState和fType分量有效
mi.fType=MFT_STRING;    //指定菜单项为字符串类型
mi.fState=MFS_ENABLED;   //指定菜单项的状态为活跃状态
mi.wID=0;       //指定菜单项的标识ID
mi.hSubMenu=NULL;     //指定菜单项包含的子菜单句柄
mi.hbmpChecked=NULL;    //指定菜单项选中时的位图
mi.hbmpUnchecked=NULL;   //指定菜单项未选中的位图
mi.dwItemData=0;     //指定菜单项的数据
mi.dwTypeData=szExit;     //指定菜单项的文本
mi.cch=strlen(szExit);     //指定菜单项文本的长度
hMenu=CreateMenu();
hPopupMenu=CreatePopupMenu();
InsertMenuItem(hPopupMenu,101,FALSE,&mi);
//展示一下MFT_MENUBARBREAK的用法
mi.fType|=MFT_MENUBARBREAK;
InsertMenuItem(hPopupMenu,102,FALSE,&mi);
//添加File菜单
AppendMenu(hMenu,MF_POPUP,(UINT)hPopupMenu,"&File11");
//创建一个新的弹出式菜单
hPopupMenu=CreatePopupMenu();
mi.fType&=~MFT_MENUBARBREAK;
mi.dwTypeData=szAbout;
InsertMenuItem(hPopupMenu,103,FALSE,&mi);
//添加Help菜单
AppendMenu(hMenu,MF_POPUP,(UINT)hPopupMenu,"&Help11");
//将新创建的菜单设置为窗口菜单
//hOldMenu=GetMenu(hWnd);
SetMenu(hWnd,hMenu); 
//不再使用该菜单,以后先恢复以前的菜单,然后再将其删除,
//SetMenu(hWnd,hOldMenu);
//DestroyMenu(hMenu);
 
6. HMENU LoadMenu(HINSTANCE hlnstance,LPCTSTR lpMenuName)
函数功能:该函数从与应用事例相联系的可执行文件(.EXE)中加载指定的菜单资源。
  函数原型:HMENU LoadMenu(HINSTANCE hlnstance,LPCTSTR lpMenuName);
  参数:
  hlnstance:含有被加载菜单资源的事例模块的句柄。
  LpMenuName:指向含有菜单资源名的以空结束的字符串的指针。同时,此参数可由低位字上的资源标识符和高位字上的零组成。要创建此值,用MAKEINTRESOURCE宏。
  返回值:如果函数调用成功,返回值是菜单资源句柄;如果函数调用失败,返回值是NULL。若想获得更多的错误信息,请调用GetLastError函数。
  备注:关闭应用程序之前,用函数DestroyMenu来销毁菜单并释放加载菜单占用的内存。Windows CE 1.0不支持层叠式菜单。Windows CE 2.0及更高版本支持层叠式菜单。
HMENU hMenu,hOldMenu;
    //装载ID标识为IDM_TEST的一个新创建的菜单
   hInst = hInstance;
    hMenu=LoadMenu(hInst,(LPCTSTR)IDM_TEST);
    hOldMenu=GetMenu(hWnd);
    SetMenu(hWnd,hMenu);
    //不再使用该新菜单以后恢复窗口以前的菜单
    //SetMenu(hWnd,hOldMenu);
 
7.HMENU LoadMenuIndirect (const MENUTEMPLATE *lpMenuTemplate // Menu的内存地址)
HRSRC hRsrc;
    HGLOBAL hGlobal;
    HMENU hMenu;
    void* pMenu;
    //从当前进程实例中查找标识为IDM_TEST的菜单资源
    //IDM_TEST为一个新创建的菜单资源标识ID
    hRsrc=FindResource(hInst,(LPCTSTR)IDM_TEST,RT_MENU);
    //装载找到的菜单资源
    hGlobal=LoadResource(hInst,hRsrc);
    //锁定已装载的菜单资源,从而获取指向资源的指针
    pMenu=LockResource(hGlobal);
    //由pMenu指针指定的资源来创建一个菜单
    hMenu=LoadMenuIndirect((CONST MENUTEMPLATE*)pMenu);
    SetMenu(hWnd,hMenu);
 
8.BOOL DestroyMenu(HMENU hMenu);
函数动能:该函数销毁指定的菜单,并释放此菜单占用的存储器。
  函数原型:BOOL DestroyMenu(HMENU hMenu);
  参数:
  hMenu:要销毁的菜单的句柄。
  返回值:如果函数调用成功,返回非零值;如果函数调用失败,返回值是零。若想获得更多的错误信息,请调用GetLastError函数。
  备注:一个应用程序在关闭之前,必须调用函数DestroyMenu来销毁一个没被分配给窗口的菜单。分配给窗口的菜单,当应用程序关闭时,被自动销毁。
可以利用CMenu的成员函数DeleteMenu.删除指定菜单项,或者弹出菜单。 
就看你用什么,调用DeleteMenu。如果用菜单栏的指针GetMenu()调用DeleteMenu,删除的是弹出菜单,如 
果你用子菜单GetSubMenu的指针,调用DeleteMenu,删除的是菜单项。 

9.BOOL DeleteMenu( HMENU hMenu ,UINT nPosition, UINT nFlags ); 
参数:菜单项或弹出菜单,所在的ID号或索引号,由第二个参数决定访问方式; 
备注:只要一个菜单被修改,无论它是否在显示窗口里,应用程序都必须调用函数DrawMenuBar。
在CMainFrame::OnCreate中添加以下代码: 
GetMenu()->DeleteMenu(1,MF_BYPOSITION);//删除弹出菜单 
GetMenu()->GetSubMenu(1)->DeleteMenu(ID_FILE_SAVE,MF_BYCOMMAND);//删除指定菜单项 
HMENU hMenu;
hMenu=LoadMenu(hInst,(LPCTSTR)IDM_TEST);
//IDM_TEST为自己创建的一个菜单资源,该菜单中包含标识ID为IDM_EXIT的菜单项。
SetMenu(hWnd,hMenu);
//使用该菜单
DeleteMenu(hMenu,IDM_EXIT,MF_BYCOMMAND);
SetMenu(hWnd,hMenu);
 
 
10.RemoveMenu(HMENU hMenu ,UINT nPosition, UINT nFlags )
参数:菜单项或弹出菜单,所在的ID号或索引号,由第二个参数决定访问方式; 
备注:只要一个菜单被修改,无论它是否在显示窗口里,应用程序都必须调用函数DrawMenuBar。
 HMENU hMenu;
hMenu=GetMenu(hWnd);
//下面的语句将删除窗口菜单中Help这一列主菜单
RemoveMenu(hMenu,0,MF_BYPOSITION);
SetMenu(hWnd,hMenu);
 
11.HMENU GetSystemMenu(HWND hWnd,BOOL bRevert);
函数功能:该函数允许应用程序为复制或修改而访问窗口菜单(系统菜单或控制菜单)。
  函数原型:HMENU GetSystemMenu(HWND hWnd,BOOL bRevert);
  参数:
  hWvd:拥有窗口菜单拷贝的窗口的句柄。
  BPevert:指定将执行的操作。如果此参数为FALSE,GetSystemMenu返回当前使用窗口菜单的拷贝的句柄。该拷贝初始时与窗口菜单相同,但可以被修改。
  如果此参数为TRUE,GetSystemMenu重置窗口菜单到缺省状态。如果存在先前的窗口菜单,将被销毁。
  返回值:如果参数bRevert为FALSE,返回值是窗口菜单的拷贝的句柄:如果参数bRevert为TRUE,返回值是NULL。
  备注:任何没有用函数GetSystemMenu来生成自己的窗口菜单拷贝的窗口将接受标准窗口菜单。
  窗口某单最初包含的菜单项有多种标识符值,如SC_CLOSE,SC_MOVE和SC_SIZE。
  窗口菜单上的菜单项发送WM_SYSCOMMAND消息。
  所有预定义的窗口菜单项的标识符数大于OxFOOO。如果一个应用程序增加命令到窗口菜单,应该使用小于OxFOOO的标识符数。
  系统根据状态自动变灰标准窗口菜单上的菜单项。应用程序通过响应在任何某单显示之前发送的WM_INITMENU消息来实现选取和变灰。
  Windows CE环境下,不支持系统菜单,但GetSyemMenu以宏的方式实现,以保持和已存在代码的兼容性。可以使用该宏的返回菜单句柄使关闭框无效,与在Windows桌面平台上一样。Windows CE下的返回值没有其他用处。参数bRevert无用。
  HMENU hSysMenu;
hSysMenu=GetSystemMenu(hWnd,FALSE);
DeleteMenu(hSysMenu,0,MF_BYPOSITION);
//使用下面这个语句来恢复系统菜单
//GetSystemMenu(hWnd,TRUE); 
 
12.HMENU GetMenu(HWND hWnd)
函数功能:该函数取得分配给指定窗口的菜单的句柄。
  函数原型:HMENU GetMenu(HWND hWnd);
  参数:
  hWnd:其菜单句柄被取得的窗口的句柄。
  返回值:返回值是菜单的句柄。如果给定的窗口没有菜单,则返回NULL。如果窗口是一个子窗口,返回值无定义。
HMENU hMenu;
hMenu=GetMenu(hWnd);
 
13.HMENU GetSubMenu(HMENU hMenu,int nPos);
函数功能:该函数取得被指定菜单激活的下拉式菜单或子菜单的句柄。
  函数原型:HMENU GetSubMenu(HMENU hMenu,int nPos);
  参数:
  hMenu:菜单句柄。
  nPos:激活下拉式菜单或子菜单的菜单项相对于零的位置。
  返回值:如果函数调用成功,返回值是菜单项激活的下拉式菜单或子菜单的句柄。如果菜单项没有激活一个下拉式菜单或子菜单,返回值是NULL。
POINT pt;
 HMENU hMenu,hSubMenu;
  //获取当前单击鼠标右键位置的坐标(在屏幕坐标系中)
  pt.x=LOWORD(lParam);
  pt.y=HIWORD(lParam);
  //将屏幕坐标系中的坐标转换到客户坐标系中
  ClientToScreen(hWnd,&pt);
  //获取窗口菜单的一个子菜单,并且将其显示出来
  hMenu=GetMenu(hWnd);
  hSubMenu=GetSubMenu(hMenu,1);
  TrackPopupMenu(hSubMenu,TPM_LEFTALIGN|TPM_TOPALIGN|TPM_RETURNCMD,
     pt.x,pt.y,0,hWnd,NULL);
 
14. BOOL SetMenuItemInfo(HMENU hMenu,UINT uItem,  BOOL fByPosition,    LPMENUITEMINFO lpmii)
 
函数原型:BOOL SetMenuItemInfo(HMENU hMenu,UINT uItem,  BOOL fByPosition,    LPMENUITEMINFO lpmii)
为一个菜单条目设置指定的信息,具体信息保存于MENUITEMINFO结构中)
参数 类型及说明:
hMenu Long,菜单句柄
un Long,菜单条目的菜单ID或位置
bool Boolean,如un指定了条目的位置,就为TRUE;如指定的是菜单ID,就为FALSE
lpcMenuItemInfo MENUITEMINFO,用于设置目标菜单条目的特征CMenu::SetMenuItemInfo(可以改变设置菜单项目的相关信息)

 返回值:
Long,TRUE(非零)表示成功,否则返回零。会设置GetLastError    

15.BOOL WINAPI GetMenuItemInfo(HMENU hMenu,UINT uItem,BOOL fByPosition,LPMENUITEMINFO lpmii);

typedef struct tagMENUITEMINFO {

    UINT          cbSize; //本结构体物理大小,以byte为单位,其值实际上为48

    UINT          fMask; //确定想要查询或设置菜单项的哪能些内容

    UINT          fType; //菜单格式类型

    UINT          fState;// 菜单状态:Enabled、Disabled or Grayed

    UINT          wID; //命令标识符

    HMENU       hSubMenu; //子菜单句柄,若无子菜单则为NULL

    HBITMAP     hbmpChecked; //根据这两个域值,可以自定义菜单项被选定时的标记,

    HBITMAP     hbmpUnchecked; //而不一定要是’√’或空白

    DWORD      dwItemData;//由English翻译为:应用程序定义的与菜单项相关的值(我也不明白)

LPTSTR       dwTypeData; //菜单资源内容指针,指向String or BitMap or SEPARATOR资源

UINT          cch; //若菜单项为MFT_STRING类型,则此项为dwTypeData长度

HBITMAP     hbmpItem;//在调试程序时发现有此一项

} MENUITEMINFO, FAR *LPMENUITEMINFO;
 
memset(&mii,   0,   sizeof(mii));  
char szAbout[16];
sprintf(szAbout, "%s","About12");
hMenu=GetMenu(hWnd);
hSubMenu=GetSubMenu(hMenu,0);
mii.cbSize=sizeof(MENUITEMINFO);
mii.fMask= MIIM_TYPE;
GetMenuItemInfo(hSubMenu,0,MF_BYPOSITION,&mii);
mii.dwTypeData=szAbout;
mii.cch=strlen(szAbout);
SetMenuItemInfo(hSubMenu,0,MF_BYPOSITION,&mii);
 
16.BOOL SetMenuDefaultItem(HMENU hMenu,UINT nItem,UINT fByPos); //缺省菜单项用黑体标出
hMenu
Long,菜单句柄
uItem
Long,欲设为默认菜单条目的一个条目的位置或菜单ID。如果为-1,表示清除当前的默认条目
fByPos
Long,如uItem是条目的位置,就为TRUE;如果是菜单ID,就为FALSE

16.UINT GetMenuDefaultItem(HMENU hMenu,UINT fByPos,UINT gmddiFlags); //缺省菜单项用黑体标出
hMenu
Long,菜单的句柄
fByPos
Long,如果为TRUE,表示接收条目在菜单中的位置;FALSE表示接收它的菜单ID
gmdiFlags
Long,下述标志之一:
GMDI_GOINTOPOPUPS
如默认条目是弹出菜单,这个函数就会在其中搜索一个默认的菜单条目
GMDI_USEDISABLED
指明自己在搜索过程中不想跳过被禁止的菜单条目

18 UINT GetMenuItemID(int nPos) const
如果成功,则返回弹出菜单中指定项的ID号。若指定项为弹出菜单(对应于弹出菜单内的项),那么返回值为-1。否则如果nPos对应于SEPARATOR菜单项,那么返回值为0。

参数:
nPos 指定将要获取ID号菜单项的位置(以0为基数)。


说明:获取由nPos指定位置的菜单项的菜单项标识符。
HMENU hMenu,hSubMenu;
MENUITEMINFO mi;
int id;
char szMain[16],szSub[16],szOutput[32];

hMenu=GetMenu(hWnd);
mi.cbSize=sizeof(MENUITEMINFO);
mi.fMask=MIIM_TYPE;
mi.dwTypeData=szMain;
mi.cch=16;
GetMenuItemInfo(hMenu,0,TRUE,&mi);

mi.dwTypeData=szSub;
mi.cch=16;
hSubMenu=GetSubMenu(hMenu,0);
GetMenuItemInfo(hSubMenu,0,TRUE,&mi);

id=GetMenuItemID(hSubMenu,0);
sprintf(szOutput,"%s/%s的ID:%d",szMain,szSub,id);
 
19.int GetMenuItemCount(HMENU hMenu);
GetMenuItemCount 获取hMenu中的表项数
HMENU hMenu,hSubMenu;
int num;
hMenu=GetMenu(hWnd);
num=GetMenuItemCount(hMenu);
 
20BOOL GetMenuItemRect(hwnd hWnd,HMENU hMenu,UINT nItem , LPRECT lprcItem)
获取制定菜单项的大小矩形
HMENU hMenu;
RECT rect,rect1;
HDC hDC;
//获取整个窗口的DC
hDC=GetWindowDC(hWnd);
hMenu=GetMenu(hWnd);
//计算出菜单项矩形在窗口坐标系下的值
GetMenuItemRect(hWnd,hMenu,0,&rect);//说明rect的系统坐标
GetWindowRect(hWnd,&rect1);
int height,width;
width=rect.right-rect.left;
height=rect.bottom-rect.top;
rect.left-=rect1.left;
rect.top-=rect1.top;
rect.right=rect.left+width;
rect.bottom=rect.top+height;
MoveToEx(hDC,rect.left,rect.top,NULL);
LineTo(hDC,rect.right,rect.bottom);
MoveToEx(hDC,rect.right,rect.top,NULL);
LineTo(hDC,rect.left,rect.bottom);
   break;
 
21.BOOL HiliteMenuItem(hwnd hWnd,HMENU hMenu,UINT wIDHiliteItem  , UINT wHilite)
控制顶级菜单条目的加亮显示状态
  [参数表]
  hwnd ----------- Long,拥有顶级菜单的一个窗口的句柄
  hMenu ---------- Long,hwnd窗口的顶级菜单的句柄
  wIDHiliteItem -- Long,欲加亮或撤消加亮的菜单条目的标识符。倘若在wHilite参数中设置了MF_BYCOMMAND标志,这个参数就用于指定要改变的菜单条目的命令ID。如果设置的是MF_BYPOSITION标志,这个参数就用于指定条目在菜单中的位置(第一个条目的位置为0)
  wHilite -------- Long,一系列常数标志的组合。其中包括MF_BYCOMMAND或MF_BYPOSITION,指出要改变的条目。也包括MF_HILITE,用于设置加亮状态;或者MF_UNHILITE,用于撤消加亮状态
HMENU hMenu;
hMenu=GetMenu(hWnd);
HiliteMenuItem(hWnd,hMenu,0,MF_BYPOSITION|MF_HILITE);
 
22. DWORD CheckMenuItem(HMENU hmenu, UINT uIDCheckItem, UINT uCheck); 
函数功能:该函数取得与指定菜单项相联系的菜单标志。如果该菜单项打开了一个子菜单,该函数也返回子菜单里的菜单项数。
  函数原型:DWORD CheckMenuItem(HMENU hmenu, UINT uIDCheckItem, UINT uCheck); 
  参数:
  hmenu:含有其菜单项的标志将被提取得的菜单的句柄。
  uIDCheckItem:制定要修改的菜单项。
  uCheck:表示标记的状态。此参数可取下列值之一:
  MF_BYCOMMAND:表示参数uId给出菜单项的标识符。如果MF_BYCOMMAND和MF_BYPOSITION都没被指定,则MF_BYCOMMAND是缺省值。
  MF_BYPOSITION:表示参数uId给出菜单项相对于零的位置。
  返回值:如果指定的项不存在,返回值是OXFFFFFFFF;如果菜单项打开了一个子菜单,则返回值的低位含有与菜单相联系的菜单标志,高位含有子菜单的项数。否则,返回值是莱单标志的掩码(布尔OR)。
  下面列出与菜单项相关的菜单标志。
  MF_CHECKED:放置选取标记于菜单项旁边(只用于下拉式菜单、子菜单或快捷菜单)。
  MF_DISABLED:使菜单项无效。MF_GRAYED:使菜单项无效并交灰。MF_HILITE:加亮菜单项。
  MF_MENUBARBREAK:对下拉式菜单、子菜单和快捷菜单,新列和旧列由垂直线隔开,其余功能同MF_MENUBREAK标志。
  MF_MENUBREAK:将菜单项放于新行(对菜单条)或无分隔列地放于新列(对下拉式菜单、子菜单或快捷菜单)。
  MF_SEPARATOR:创建一个水平分隔线(只用于下拉式菜单、子菜单或快捷菜单)。
  MF_UNCHECKED: Acts as a toggle with MF_CHECKED to remove a check mark next to the item
HMENU hMenu,hSubMenu;
hMenu=GetMenu(hWnd);
hSubMenu=GetSubMenu(hMenu,0);
CheckMenuItem(hSubMenu,0,MF_BYPOSITION|MF_CHECKED);
 
23. BOOL EnableMenuItem(HMENU hMenu,UINT uIDEnableItem, UINT uEnable);
  返回值 : BOOL 判断是否成功
  参数表 :
  参数 类型及说明
  hMenu ,菜单句柄
  wIDEnableItem ,欲允许或禁止的一个菜单条目的标识符。如果在wEnable参数中设置了MF_BYCOMMAND标志,这个参数就代表欲改变菜单条目的命令ID。如设置的是MF_BYPOSITION,则这个参数代表菜单条目在菜单中的位置(第一个条目肯定是零)
  wEnable ,参考ModifyMenu函数中的菜单常数标志定义表,其中列出了允许使用的所有常数。对于这个函数,只能指定下述常数:MF_BYCOMMAND,MF_BYPOSITION,MF_ENABLED,MF_DISABLED以及MF_GRAYED
  这些值有下列含义:
  
· MF_BYCOMMAND 指定参数给出已存在的菜单项的命令ID号。此为缺省值。 · MF_BYPOSITION 指定参数给出已存在菜单项的位置。第一项所在的位置是0。 · MF_DISABLED 使菜单项无效,以便它不能被选择,但不变灰。 · MF_ENABLED 使菜单项有效,以便它能够被选择,并可从变灰的状态中恢复出来。 · MF_GRAYED 使菜单项无效,以便它不能被选择并同时变灰。
  注解
  如指定的菜单条目依附了一个弹出式菜单,那么整个弹出式菜单都会受到影响
  说明:
  使菜单项有效、无效或变灰。CreateMenu,InsertMenu,ModifyMenu和LoadMenuIndirect成员函数同时也设置菜单项的状态(有效、无效、或变灰)。
  使用MF_BYPOSITION的值需要应用恰当的CMenu对象。若菜单条的CMenu被使用,那么顶层菜单项(菜单条中的某项)将受影响。如果为了在弹出菜单或嵌套的弹出菜单中通过位置来设置项的状态,那么应用必须指定弹出菜单的CMenu。
  当应用指定了MF_BYCOMMAND标志,那么Windows将检测所有的属于CMenu的弹出菜单项。因此,除非当前正在复制菜单项,那么使用菜单条的CMenu是非常有效的。
HMENU hMenu,hSubMenu;
hMenu=GetMenu(hWnd);
hSubMenu=GetSubMenu(hMenu,0);
CheckMenuItem(hSubMenu,0,MF_BYPOSITION|MF_DISABLED|MF_GRAYED );
 
24 BOOL CheckMenuRadioItem(HMEN hMENU,UINT idFirst,UINT idLast,UINT idCheck,UINT uFlags);
函数功能:该函数校核一个指定的菜单项并使其成为一个圆按钮项。同时不校核相关组里的其他菜单项并清除这些项的国按钮的类型标志。
  函数原型:BOOL CheckMenuRadioItem(HMEN hMENU,UINT idFirst,UINT idLast,UINT idCheck,UINT uFlags);
  参数:
  hMenu:包含一组菜单项的菜单的句柄。
  idFirst:菜单组里第一个菜单项的标识符或位置。
  idLast:菜单组里最后一个菜单项的标识符或位置。
  idCheck:要选取的菜单项的标识符或位置。
  uFlag:指定idFirst,idLast,idCheck含义的值。如果此参数为MF_BYCOMMAND,则其他参数指定菜单项标识符。如果此参数为MF_BYPOSITION,则其他参数指定菜单项位置。
  返回值:如果函数调用成功,返回值非零。如果函数调用失败,返回值为零。若想获得更多的错误信息,请调用GetLastError函数。
  备注:CheckMenuRadioItem设置了MFT_RADIOCHECK类型标志,并为由idCheck指定的项设置 MFS_CHECKED状态,同时,清除组里所有其他项目的上述两个标志。被选取的项用项目目标表示,而不是用复选标记目标。要得到更多的关于菜单项类型和状态标志的信息,参看MENUITEMINFO结构。
HMENU hMenu,hSubMenu;
    hMenu=GetMenu(hWnd);
  hSubMenu=GetSubMenu(hMenu,0);
  InsertMenu(hSubMenu,0,MF_STRING,101,"Test1");
  InsertMenu(hSubMenu,1,MF_STRING,101,"Test2");
  InsertMenu(hSubMenu,2,MF_STRING,101,"Test3");
  
  CheckMenuItem(hSubMenu,0,MF_BYPOSITION|MF_CHECKED);
  CheckMenuItem(hSubMenu,2,MF_BYPOSITION|MF_CHECKED);
  break;

  //注意这里的菜单句柄必须重新定义,而不能使用上面的hMenu和hSubMenu
  //因为此时是第二次进入该窗口过程,上面的非静态局部变量已经不再可用
  HMENU hMenu1,hSubMenu1;
  hMenu1=GetMenu(hWnd);
  hSubMenu1=GetSubMenu(hMenu1,0);
  CheckMenuRadioItem(hSubMenu1,0,3,1,MF_BYPOSITION);
  break;
 
24.UINT MenuItemFromPoint(HWND hWnd,HMENU hMenu,POINT ptScreen)
判断指定点是否有一个菜单项。
HMENU hMenu;
POINT pt;
int  pos;
MENUITEMINFO mi;
RECT rect;
//获取窗口的外框矩形坐标
GetWindowRect(hWnd,&rect);
//定位第一个菜单项的坐标
pt.x=rect.left+10;
pt.y=rect.top+30;
hMenu=GetMenu(hWnd);
if((pos=MenuItemFromPoint(hWnd,hMenu,pt))>=0){
  char szName[16];
  mi.cbSize=sizeof(MENUITEMINFO);
  mi.fMask=MIIM_TYPE;
  mi.dwTypeData=szName;
  mi.cch=16;
  GetMenuItemInfo(hMenu,pos,TRUE,&mi);
  MessageBox(NULL,szName,"MenuItemFromPoint",MB_OK);
 
25BOOL SetMenu(HWND hWnd,HMENU hMenu)
函数功能:该函数分配一个新菜单到指定窗口。
  函数原型:BOOL SetMenu(HWND hWnd,HMENU hMenu);
  参数:
  hWnd:菜单被分配到其中的窗口的句柄。
  HMenu:新菜单的句柄。如果菜单参数为NULL,则窗口的当前菜单被删除。
  返回值:如果函数调用成功,返回非零值;如果函数调用失败,返回值是零。若想获得更多的错误信息,请调用GetLastError函数。
  备注:窗口被重画来反映菜单的修改。函数SetMenu替换原来的菜单(如果存在),但并不将其销毁。应用程序必须调用函数DestroyMenu来销毁菜单。
 
26.BOOL SetMenuItemBitmaps(UINT nPosition,UINT nFlags,const CBitmap* pBmpUnchecked,const CBitmap* pBmpChecked)
设置一幅特定位图,令其在指定的菜单条目中使用,代替标准的复选符号(√)。位图的
大小必须与菜单复选符号的正确大小相符,这个正确大小可以由GetMenuCheckMarkDimens
ions函数获得 
返回值 
Long,非零表示成功,零表示失败。会设置GetLastError 
参数表 
参数 类型及说明 
hMenu Long,菜单句柄 
nPosition Long,欲设置位图的一个菜单条目的标识符。如在wFlags参数中指定了
MF_BYCOMMAND,这个参数就代表欲改变的菜单条目的命令ID。如设置的是MF_BYPOSITION
,这个参数就代表菜单条目在菜单中的位置(第一个条目的位置为零) 
wFlags Long,常数MF_BYCOMMAND或MF_BYPOSITION,取决于nPosition参数 
hBitmapUnchecked Long,撤消复选时为菜单条目显示的一幅位图的句柄。如果为零,表
示不在未复选状态下显示任何标志 
hBitmapChecked Long,复选时为菜单条目显示的一幅位图的句柄。可设为零,表示复选
时不显示任何标志。如两个位图句柄的值都是零,则为这个条目恢复使用默认复选位图 
 
27 HMENU Detach(); 
  MFC类里CMENU类的成员函数。功能是切断一个CWnd对象和一个有效窗口的联系。
  由于WNDCLASS其实和CWnd根本没有什么关系,它们之间只是通过CWnd的成员HWND联系起来的。Detach的作用是切断一个CWnd对象和一个有效窗口的联系。因为CWnd是C++的对象,C++的对象有一个生存期的概念,脱离了该对象的作用域,这个对象就要被销毁,但是Windows对象没有这个特点,当销毁CWnd对象的时候,我们不一定希望WNDCLASS一起被销毁,那么在此之前,我们就先要把这个联系切断。
  当我们建立了一个局部的菜单对象后,比如 在一个窗口类的函数里建立了一个局部菜单对象,当这个窗口函数的生命周期结束时,如果不希望菜单对象也被销毁,就要用detach()函数把菜单句柄和这个菜单对象分离。这样,当局部的菜单对象被销毁时,它不会销毁一个它不具备拥有权的菜单。
SM_CXMENUCHECK, SM_CYMENUCHECK 以像素为单位计算的菜单选中标记位图的尺寸
CFrameWnd::m_bAutoMenuEnable  = FALSE; (系统默认的为TRUE);
菜单命令消息路由的具体过程:
当点击某个菜单项时,框架类先接受菜单消息,框架类在交给视类处理。如果视类不作处理,则交给文档类处理。文档类不处理,则交还给视类,视类
交还给框架类,框架类交还给应用程序。
 
一。创建非Popup类型菜单,不使用资源。 
(一)创建非下拉菜单。 
1。在窗口类的OnCreate函数里创建CMenu对象。如果是创建运用程序主框架窗口 
的话,也可以在InitInstance()函数里。 
2。声明一个CMenu对象:CMenu MyMenu; 
3。调用MyMenu.CreateMenu()或MyMenu.LoadMenu() 
4。调用若干次MyMenu.AppendMenu()或MyMenu.InsertMenu(),每调用一次创建一 
个菜单项。 
5。调用MyMneu.SetMenu()将菜单Attach到窗口上。 
6。调用MyMenu.Detach()。 
int CMyWnd::OnCreate( LPCREATESTRUCT lpCreateStruct )  
{  
  CMenu MyMenu;  
  MyMenu.CreateMenu();  
  MyMenu.AppendMenu(MF_STRING,IDM_MENU0,"文件");  
  MyMenu.InsertMenu(IDM_MENU2,MF_BYCOMMAND,IDM_ITEM0,"有关");  
  this->SetMenu(&MyMenu);  
  MyMenu.Detach();  
  return 0;  
}
用Detach()使菜单和MyMenu对象脱离关系,因为MyMenu对象是一个局部变量,马上就要超出作用域了,这一步是必须的。  
而SetMenu 是CMyWnd的成员函数,是建立看得见的菜单同CMyWnd::m_cmenu的关系
DestroyMenu则根据m_cmenu 销毁看得见的菜单。
备注:一个应用程序在关闭之前,必须调用函数DestroyMenu来销毁一个没被分配给窗口的菜单。分配给窗口的菜单,当应用程序关闭时,被自动销毁。 

(二)创建下拉菜单,不使用资源。 
这种菜单当鼠标移动到菜单条目上面点击时不是去执行某段程序,而是弹出 
一个下拉菜单。这需要用前面的方法创建两个菜单。第一个是鼠标未点击时看到 
的那个菜单,另一个就是扮演下拉菜单的菜单。例子: 
int CMyWnd::OnCreate( LPCREATESTRUCT lpCreateStruct ) 
CMenu MyMenu0,MyMenu1; 
//下面这几条创建下拉菜单 
MyMenu1.CreateMenu(); 
MyMenu1.AppendMenu(MF_STRING,IDM_ITEM0,"拷贝"); 
MyMenu1.AppendMenu(MF_STRING,IDM_ITEM1,"剪切"); 
MyMenu1.AppendMenu(MF_STRING,IDM_ITEM2,"粘贴"); 
MyMenu1.AppendMenu(MF_SEPARATOR,IDM_ITEM3,""); 
MyMenu1.AppendMenu(MF_STRING,IDM_ITEM4,"全选"); 
MyMenu1.AppendMenu(MF_SEPARATOR,IDM_ITEM5,""); 
MyMenu1.AppendMenu(MF_STRING,IDM_ITEM6,"删除"); 
//下面这两条创建鼠标未点击时看到的那个菜单 
//其中第二句将下拉菜单张贴到第一个菜单上。 
MyMenu0.CreateMenu(); 
MyMenu0.AppendMenu(MF_POPUP,(UINT)MyMenu1.m_hMenu,"编辑"); 

this->SetMenu(&MyMenu0);//将菜单张贴到窗口上 
MyMenu0.Detach();//必须有 
MyMenu1.Detach();//必须有 
return 0; 

二。创建Popup类型的菜单,也不用资源。 
很多程序里,只要用鼠标右键点一下窗口客户区,就会在鼠标的位置弹出一 
个菜单,这叫右键菜单。我们可以用CMenu类来制作。 
制作这种菜单比制作第一类菜单稍微复杂点。首先要在窗口类里加个成员变 
量:CMenu *MyMenu2; 
然后在窗口类的构造函数里(或OnCreate()函数里)加上创建菜单的语句,再 
在析构函数里加上销毁菜单的语句,最后在OnRButtonDown()函数里加上显示菜单 
的语句。 
创建菜单时,CMenu类对象应该用new来分配。 
例子: 

CMyWnd::CMyWnd() 
//CMyWnd是从CWnd派生来的。 
//先把菜单创建起来。 
MyMenu2=new CMenu; 
MyMenu2->CreatePopupMenu(); 
MyMenu2->AppendMenu(MF_STRING,IDM_ITEM0,"拷贝"); 
MyMenu2->AppendMenu(MF_STRING,IDM_ITEM1,"剪切"); 
MyMenu2->AppendMenu(MF_STRING,IDM_ITEM2,"粘贴"); 
MyMenu2->AppendMenu(MF_SEPARATOR,IDM_ITEM3,""); 
MyMenu2->AppendMenu(MF_STRING,IDM_ITEM4,"全选"); 
MyMenu2->AppendMenu(MF_SEPARATOR,IDM_ITEM3,""); 
MyMenu2->AppendMenu(MF_STRING,IDM_ITEM5,"删除"); 

CMyWnd::~CMyWnd() 
MyMenu2->DestroyMenu();//销毁菜单所占用的系统资源 
delete MyMenu2;//销毁菜单类对象 
void CMyWnd::OnRButtonDown(UINT nFlags, CPoint point) 
RECT rect; 
GetWindowRect(&rect); 
//显示菜单 
MyMenu2->TrackPopupMenu(TPM_RIGHTALIGN,point.x+rect.left,point.y+ 
rect.top,this,NULL); 

三。使用资源编辑器做好的菜单,只能做非POPUP类型菜单。 
如果使用资源的话,创建菜单确实非常简单了,只须在窗口类的OnCreate() 
函数里加几句话就行了: 
int CMyWnd::OnCreate( LPCREATESTRUCT lpCreateStruct ) 
CMenu MyMenu3; 
MyMenu3.LoadMenu(IDR_MENU1);//IDR_MENU1是你的菜单的资源ID。 
this->SetMenu(&MyMenu3);   // this == CMyWnd*
MyMenu3.Detach(); 
return 0; 

MFC类里CMENU类的成员函数。功能是切断一个CWnd对象和一个有效窗口的联系。   由于WNDCLASS其实和CWnd根本没有什么关系,它们之间只是通过CWnd的成
员HWND联系起来的。Detach的作用是切断一个CWnd对象和一个有效窗口的联系。因为CWnd是C++的对象,C++的对象有一个生存期的概念,脱离了该对象的作用域,这
个对象就要被销毁,但是Windows对象没有这个特点,当销毁CWnd对象的时候,我们不一定希望WNDCLASS一起被销毁,那么在此之前,我们就先要把这个联系切断。  
当我们建立了一个局部的菜单对象后,比如 在一个窗口类的函数里建立了一个局部菜单对象,当这个窗口函数的生命周期结束时,如果不希望菜单对象也被销毁,就要用
detach()函数把菜单句柄和这个菜单对象分离。这样,当局部的菜单对象被销毁时,它不会销毁一个它不具备拥有权的菜单。


m_menu.CreateMenu();
CString c_menustr;
while (! m_pRecord->ADOEOF)
{
c_menustr = m_pRecord->GetCollect("菜单名称").bstrVal;
//menu.AppendMenu(MF_STRING,-1,c_menustr);
LoadSubMenu(&m_menu,c_menustr);
m_pRecord->MoveNext();
}
SetMenu(&m_menu);

void  LoadSubMenu(CMenu* m_menu,CString str)
{
CMenu m_tempmenu;
m_tempmenu.CreateMenu();

while (!m_record->ADOEOF)
{
CString c_menustr = m_record->GetCollect("菜单名称").bstrVal;
if(IsHaveSubMenu(c_menustr))
{
LoadSubMenu(&m_tempmenu,c_menustr);
}
else
m_tempmenu.AppendMenu(MF_STRING,-1,c_menustr);
m_record->MoveNext();
}

m_menu->AppendMenu(MF_POPUP,(UINT)m_tempmenu.m_hMenu,str);
m_tempmenu.Detach();
}


自定义菜单时,需要
(1)主窗口
m_menu.AttatchMenu(this->GetMenu()->GetSafeHmenu());
m_menu.ChangeMenuItem(&m_menu,TRUE);
或是m_menu.LoadMenu(IDR_POPUPMENU);
m_menu.ChangeMenuItem(&m_menu);


ON_WM_DRAWITEM()
ON_WM_MEASUREITEM()
afx_msg void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct);
afx_msg void OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct);

void CMainFrame::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)  // 
{
m_menu.DrawItem(lpDrawItemStruct);
// CFrameWnd::OnDrawItem(nIDCtl, lpDrawItemStruct);
}

void CMainFrame::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct) 
{
m_menu.MeasureItem(lpMeasureItemStruct);
// CFrameWnd::OnMeasureItem(nIDCtl, lpMeasureItemStruct);
}

void CMainFrame::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct) 

lpMeasureItemStruct 是指向MEASUREITEMSTRUCT结构体的指针,其成员变量
UINT CtlType; // 要绘制的类型
UINT itemID; // 菜单选项ID
UINT itemWidth; //菜单选项宽度
UINT itemHeight; //菜单选项高度

void CMainFrame::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)

lpDrawItemStruct 是指向DRAWITEMSTRUCT结构体的指针,其成员变量
UINT CtlType; // 要绘制的类型
UINT itemID; // 菜单选项ID
UINT itemAction; // 菜单动作
UINT itemState; // 菜单选项的当前状态
HWND hwndItem; // 顶层菜单的句柄 
HDC hDC; // 绘制设备DC 
RECT rcItem; // 菜单选项的大小
DWORD itemData; // 附加自定义数据,由AppendMenu或InsertMenu或ModifyMenu的lpszNewItem指定


WM_DRAWITEM:绘制菜单的样式
WM_MEASUREITEM:指定要绘制菜单的大小
WM_INITMENU:把框架菜单全部改成带MF_OWNERDRAW标志


(2)class CIconMenu : public CMenu

struct CMenuItemInfo
{
CString m_ItemText;//菜单项文本
int m_IconIndex;//菜单项索引
int m_ItemID;//菜单标记 -2顶层菜单,-1弹出式菜单,0分隔条,其他普通菜单
};

CMenuItemInfo m_ItemLists[MAX_MENUCOUNT]; //菜单项信息

BOOL  CIconMenu::AttatchMenu(HMENU m_hmenu)
{
this->Attach(m_hmenu);
return TRUE;
}

BOOL CIconMenu::ChangeMenuItem(CMenu* m_menu,BOOL m_Toped)
{
if (m_menu != NULL)
{
int m_itemcount = m_menu->GetMenuItemCount();
for (int i=0;i<m_itemcount;i++)
{
m_menu->GetMenuString(i,m_ItemLists[m_index].m_ItemText,MF_BYPOSITION);
int m_itemID = m_menu->GetMenuItemID(i);
if (m_itemID==-1 && m_Toped)
{
m_itemID = -2;//顶层菜单
};
m_ItemLists[m_index].m_ItemID = m_itemID;
if (m_itemID>0)
{
m_ItemLists[m_index].m_IconIndex= m_iconindex;
m_iconindex+=1;
}
m_menu->ModifyMenu(i,MF_OWNERDRAW|MF_BYPOSITION |MF_STRING,m_ItemLists[m_index].m_ItemID,(LPSTR)&(m_ItemLists

[m_index]));
m_index+=1;
CMenu* m_subMenu = m_menu->GetSubMenu(i);

if (m_subMenu)
{
ChangeMenuItem(m_subMenu);
}
}
}
return TRUE ;
}

void CIconMenu::MeasureItem( LPMEASUREITEMSTRUCT lpStruct )

void CIconMenu::DrawItem( LPDRAWITEMSTRUCT lpStruct )


响应系统菜单按键

// 相应系统的下拉菜单
void CPeculiarMenuDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if (nID == IDI_PECULIARMENU)
{
MessageBox("系统菜单","提示",MB_OKCANCEL|MB_ICONINFORMATION|MB_DEFBUTTON2);
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}

获取系统菜单
CMenu *m_pMenu = GetSystemMenu(FALSE); // GetSystemMenu(); 获取系统菜单


【VC++】在对话框中使用ON_UPDATE_COMMAND_UI更新菜单

从命令用户界面处理函数(Command UI handler)改变菜单状态(启用/禁用,选择/取消选择,更改文字)在由对话框处理时没有正常工作。

 

原因:在下拉菜单显示的时候, WM_INITMENUPOPUP消息被先发送以显示菜单项。MFC CFrameWnd::OnInitMenuPopup 函数遍历菜单项并为每个菜单项调用更新命令处

理函数(如果有的话)。菜单的外观被更新以反映它的状态(启用/禁用,选择/取消选择)。更新用户界面机制在基于对话框的应用程序中不能工作,因为CDialog没有

OnInitMenuPopup 处理函数,而使用CWnd's 默认处理函数,该函数没有为菜单项调用更新命令处理函数。

 

解决办法:

class CTestDlg : public CDialog
{
void OnInitMenuPopup(CMenu *pPopupMenu, UINT nIndex,BOOL bSysMenu);
afx_msg void OnUpdateChkckDelete(CCmdUI* pCmdUI);
afx_msg void OnUpdateChkckCut(CCmdUI* pCmdUI);
afx_msg void OnUpdateChkckCopy(CCmdUI* pCmdUI);
afx_msg void OnUpdateChkckSend(CCmdUI* pCmdUI);
afx_msg void OnUpdateChkckPaste(CCmdUI* pCmdUI);
}
1.在消息映射中添加ON_WM_INITMENUPOPUP项

[cpp] view plaincopy
BEGIN_MESSAGE_MAP(CTestDlg, CDialog)  
    //{{AFX_MSG_MAP(CTestDlg)  
.......  
    //}}AFX_MSG_MAP  
    ON_WM_INITMENUPOPUP()   
    ON_UPDATE_COMMAND_UI(ID_CHKCK_DELETE, OnUpdateChkckDelete)
    ON_UPDATE_COMMAND_UI(ID_CHKCK_CUT, OnUpdateChkckCut)
    ON_UPDATE_COMMAND_UI(ID_CHKCK_COPY, OnUpdateChkckCopy)
    ON_UPDATE_COMMAND_UI(ID_CHKCK_SEND, OnUpdateChkckSend)
    ON_UPDATE_COMMAND_UI(ID_CHKCK_PASTE, OnUpdateChkckPaste)
END_MESSAGE_MAP()  

2.在你的对话框类中添加OnInitMenuPopup成员函数且复制下列代码到该函数(注意:代码基本上是从CFrameWnd::OnInitMenuPopup(在WinFrm.cpp中)复制过来的)。

[cpp] view plaincopy
void CTestDlg::OnInitMenuPopup(CMenu *pPopupMenu, UINT nIndex,BOOL bSysMenu)  
{  
    ASSERT(pPopupMenu != NULL);  
      
    CCmdUI state;  
    state.m_pMenu = pPopupMenu;  
    ASSERT(state.m_pOther == NULL);  
    ASSERT(state.m_pParentMenu == NULL);  
      
    HMENU hParentMenu;  
    if (AfxGetThreadState()->m_hTrackingMenu == pPopupMenu->m_hMenu)  
        state.m_pParentMenu = pPopupMenu;      
    else if ((hParentMenu = ::GetMenu(m_hWnd)) != NULL)  
    {  
        CWnd* pParent = this;  
        if (pParent != NULL &&  
            (hParentMenu = ::GetMenu(pParent->m_hWnd)) != NULL)  
        {  
            int nIndexMax = ::GetMenuItemCount(hParentMenu);  
            for (int nIndex = 0; nIndex < nIndexMax; nIndex++)  
            {  
                if (::GetSubMenu(hParentMenu, nIndex) == pPopupMenu->m_hMenu)  
                {  
                    state.m_pParentMenu = CMenu::FromHandle(hParentMenu);  
                    break;  
                }  
            }  
        }  
    }  
      
    state.m_nIndexMax = pPopupMenu->GetMenuItemCount();  
    for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax;  
    state.m_nIndex++)  
    {  
        state.m_nID = pPopupMenu->GetMenuItemID(state.m_nIndex);  
        if (state.m_nID == 0)  
            continue;   
          
        ASSERT(state.m_pOther == NULL);  
        ASSERT(state.m_pMenu != NULL);  
        if (state.m_nID == (UINT)-1)  
        {  
            state.m_pSubMenu = pPopupMenu->GetSubMenu(state.m_nIndex);  
            if (state.m_pSubMenu == NULL ||  
                (state.m_nID = state.m_pSubMenu->GetMenuItemID(0)) == 0 ||  
                state.m_nID == (UINT)-1)  
            {  
                continue;        
            }  
            state.DoUpdate(this, TRUE);    
        }  
        else  
        {  
            state.m_pSubMenu = NULL;  
            state.DoUpdate(this, FALSE);  
        }  
          
        UINT nCount = pPopupMenu->GetMenuItemCount();  
        if (nCount < state.m_nIndexMax)  
        {  
            state.m_nIndex -= (state.m_nIndexMax - nCount);  
            while (state.m_nIndex < nCount &&  
                pPopupMenu->GetMenuItemID(state.m_nIndex) == state.m_nID)  
            {  
                state.m_nIndex++;  
            }  
        }  
        state.m_nIndexMax = nCount;  
    }  
}   


void CChkDlgWnd::OnUpdateChkckPaste(CCmdUI* pCmdUI)
{
CWnd* pWnd = GetFocus();
if(pWnd)
{
if( pWnd->IsKindOf( RUNTIME_CLASS(CChkckTreeView) ) )
{
m_pTreeView->OnUpdateChkckPaste(pCmdUI);
}
}
}
 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多