有关菜单的操作主要用到
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();
六、
响应
菜单
的事件
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