有关菜单的操作主要用到 CMenu 类,当然也可用相应 API 函数, CMenu 类只是 MFC API 中操作菜单的函数的封装而已。 不过能用类就尽量用类,类的组织方式好呗,代码看着也舒服。 若是 SDK 编程,那就用 API

CMenu menuMain,menu1; // 首先 定义 CMenu 对象

一、 创建菜单,有两种方法

1. LoadMenu 函数从资源加载

menuMain.LoadMenu(IDR_MAINFRAME); // 从资源加载,这里使用 SDI 的主菜单资源

2. CreateMenu 函数创建

menu1.CreateMenu();   // 创建菜单,还没有菜单项

二、 添加菜单项,可用 AppendMenu() 在菜单的最后加、 InsertMenu() 在指定 的位置加 .

// ID_TEST1 Resource.h 中定义,随便给个整数值,不要和已有的重复就行了

menu1.AppendMenu( MF_STRING ,ID_TEST1,"Test1"); // 第一项菜单项

menu1.AppendMenu( MF_STRING ,ID_TEST2,"Test2"); // 第二项菜单项

menu1.InsertMenu(1,MF_BYPOSITION|MF_STRING,

(UINT)ID_TEST1,"ID_TEST1"); // 在第二项菜单项前添加新菜单项

三、 添加子菜单

同样用 AppendMenu() InsertMenu() 函数。不过要 注意参数的设置

menu1. AppendMenu(MF_BYPOSITION| MF_POPUP |MF_STRING,

(UINT) menuMain.GetSubMenu(0) ->m_hMenu ," 子菜单 ");

// 第二个参数是菜单的句柄 HMENU

四、 删除菜单

DeleteMenu() RemoveMenu() 函数来删除指定位置的菜单 / 菜单项。

两者区别: 如果菜单项是一个弹出式菜单,那么 DeleteMenu RemoveMenu 之间的区别就很重要。 DeleteMenu 清除弹出式菜单,但 RemoveMenu 不清除它。一个是彻底的删除 , 一个只是移除 .

MSDN:  1.The   DeleteMenu   function   destroys   the   handle   to   the   menu   or   submenu   and   frees   the   memory   used   by   the   menu   or   submenu. 它使菜单或者子菜单的 handle 无效( destroys)
2.   RemoveMenu   does   not   destroy   the   menu   or   its   handle,   allowing   the   menu   to   be   reused.
可以再利用,并不从内存中将 menu 删除。

五、 添加 右键菜单

CMenu menu1;

menu1.CreatePopupMenu();     // 动态创建弹出式菜单对象

menu1.AppendMenu(MF_STRING,ID_TEST1," 菜单项 1");

menu1.AppendMenu(MF_STRING,ID_TEST2," 菜单项 2");

menu1.InsertMenu(2,MF_BYPOSITION|MF_POPUP|MF_STRING,

(UINT) menuMain.m_hMenu," 子菜单 "); // 添加子菜单

CPoint pt;

GetCursorPos(&pt);

menu1.TrackPopupMenu(TPM_RIGHTBUTTON, pt.x, pt.y, this);

menu1.DestroyMenu();

如何动态添加菜单/菜单项、子菜单、右键菜单_wizard
六、 响应 菜单 的事件

1. 若是资源中添加的菜单可用 Class Wizard 添加菜单的响应事件。

2. 若是通过代码创建的菜单,要手工实现菜单的消息映射。本例是在 CmainFrame 类中,当然也可在 View 类、 Doc 类中,基于对话框的同样也可以。

1) .h 文件中

// Generated message map functions

protected:

//{{AFX_MSG(CMainFrame)

afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);

afx_msg void OnChangmenuitem(); // 这里添加菜单命令处理函数的声明

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

2) .cpp 文件中,

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)

//{{AFX_MSG_MAP(CMainFrame)

ON_WM_CREATE()

ON_COMMAND(IDM_CHANGMENUITEM, OnChangmenuitem) // 这里添加,注意没有 ;

//}}AFX_MSG_MAP

END_MESSAGE_MAP()

void CMainFrame::OnChangmenuitem()

{

// 这里写你要如何处理的代码

……

}

其他方法:

若菜单 ID 值是连续的,最好用 ON_COMMAND_RANGE 来映射消息处理函数,可以在一个函数中处理一个范围内的所有消息。

当用户按下某个菜单项,会发出一个 WM_COMMAND 消息,而菜单项的 ID 号,就包含在参数 wParam 的低位中 .
BOOL   CYourView::OnCommand(WPARAM   wParam,   LPARAM   lParam)

{

//  TODO:   Add your specialized code here and/or call the base class
UINT   m_nItemID=LOWORD(wParam);
if   (m_nItemID==ID_YOURITEM)  //ID_YOURITEM 为你加入菜单项时指定的 ID

{
// 在这里放入响应的代码
}
return   CScrollView::OnCommand(wParam,   lParam);
}

对于右键菜单可以通过 TrackPopupMenu 的返回值来处理。在参数 uFlags 中设置 TPM_ RETURNCMD ,这样返回值就是你选择的菜单项的 ID ,然后可以根据 ID 来处理。

TrackPopupMenu(TPM_ RETURNCMD ,pt.x,pt.y,this);

MSDN If you specify TPM_RETURNCMD in the uFlags parameter, the return value is the menu-item identifier of the item that the user selected.

七、 其他

DrawMenuBar () ; // 当您改变菜单时,需要重画菜单才能显示所做的改变

GetSystemMenu () ; // 取得窗口控制窗口

GetMenu()   // 取得当前程序使用的菜单

GetSubMenu() // 取得子菜单

应使用 CMenu 类的 Detach() 成员函数从 Cmenu 对象中分离出菜单句柄,避免对象失效后程序出错。

如:

CMenu menu;

menu.CreatePopupMenu(); // 动态创建弹出式菜单对象

menu.AppendMenu(0,ID_TEST1,"Test1");

menu.AppendMenu(0,ID_TEST2,"Test2");

CMenu* menuMain = GetMenu(); // 取得程序主菜单 需在 CMainFrame 类中

menuMain->AppendMenu(MF_BYPOSITION|MF_POPUP|MF_STRING,(UINT) menu.m_hMenu ," 子菜单 1");

menu.Detach();      // 直接用 menu.m_hMenu 在运行时出错, menu 对象在这个事件结束就销毁了

DrawMenuBar();

八、 创建多列的菜单

只需要设置菜单属性break为 column或者bar 就可以重这个菜单开始进行下一列的显示了 从而实现多列显示

具体代码如下

menu1.AppendMenu(MF_STRING| MF_MENUBREAK ,ID_TEST2," 菜单项 2");

从菜单项2就开始新的一列显示剩下的菜单了

以下附加 菜单标志说明:

UNIT nFlags是菜单项类型或状态,常用的标志为:
MF_OWNERDRAW     菜单项内容由应用程序绘制,可以这制样式更丰富的菜单项
MF_POPUP     弹出式菜单
MF_SEPARATOR     菜单项为一条分隔线
MF_STRING       菜单项含一个字符串
MF_CHECKED     菜单项显示先中标记,即打勾
MF_DISABLED     禁用菜单
MF_ENABLED     启用菜单
MF_GRAYED     禁用菜单
MF_MENUBREAK        相当于Break:Column
MF_MENUBARBREAK     相当于Break:Bar