菜单就是红圈圈住的那一部分,而每一个选项是一个子菜单
例如这个
几乎每一个应用程序都需要自己的菜单(除了对话框程序),所以学习如何制作自己的菜单还有相应的响应事件就变得很重要了
菜单的创建:
找到资源视图下的Menu部分,右键添加自己的菜单就可以了。
把应用程序的菜单替换成自己的菜单:
菜单的出现是在框架创建完以后,所以我们需要在框架的
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
这个函数里设置我们自己的菜单。
如果不需要菜单:
SetMenu(NULL);
如果要加载自己的菜单:
CMenu menu; //定义菜单
menu.LoadMenu(IDR_MENU1); //载入在资源里创建好的菜单
SetMenu(&menu); //设置当前窗口的菜单
menu.Detach(); //分离资源菜单和定义的菜单
为什么会有最有一句分离呢? 这跟变量的生命周期有关。如果不分离,大括号结束,因为这两个量有关联,所以这个menu变量被回收,菜单自然也就不见了。但是分离以后,菜单已经显示在框架上了,所以有没有这个menu也是无所谓。
为自己的菜单添加事件处理:
最基本的方法就是在资源视图里,给你要添加事件的菜单项添加一个事件处理,这种方法简单粗暴,只适合少量菜单的程序。
万一我的菜单项很多,我是不是要添加很多事件处理?不,这样程序会很乱。下面介绍一种MFC提供的批处理方法:
ON_COMMAND_RANGE(ID_MENU_MAX,ID_MENU_EXIT,&CMenuView::OnMyMenu) //消息映射
void OnMyMenu(UINT nID); //函数的声明
批处理就是对于一些范围的ID,响应同一个函数。批处理发出的消息是ON_COMMAND_RANGE,特别注意,这些ID必须是连续,如果不是连续的,需要自己手动修改,注意也不要重复。
在实现函数里直接switch传进来的nID就可以了。
怎样实现这样的功能?
首先要记下是按下了哪个菜单项,我是在view类里添加的批处理,所以在view类里添加了一个成员变量
UINT m_nID:
在进入批处理函数
void CMenuView::OnMyMenu(UINT nID)
的时候,我让
m_nID = nID;
这时便知道了是哪个菜单项被按下
要想知道哪个菜单项被选中,就得在第二次按菜单的时候才能看出来,这里还是有一个消息
ON_UPDATE_COMMAND_UI_RANGE(ID_MENU_MAX,ID_MENU_EXIT, &CMainFrame::OnMenuOnMy) //消息映射
afx_msg void OnMenuOnMy(CCmdUI *pCmdUI); //函数声明
ON_UPADTE_COMMAND_UI_RANGE 也是一个批处理消息,是更新用户界面处理的消息
//点击哪个菜单项哪个打对勾
void CMainFrame::OnMenuOnMy(CCmdUI *pCmdUI)
{
CMenuView* pID = (CMenuView*)GetActiveView(); //定义一个视图类的指针获取当前活动视图(因为我这个update写在了框架里)
if (pCmdUI->m_nID == pID->getID()) //pCmdUI这个结构体的m_nID是否和我们点击的ID相同
{
pCmdUI->SetCheck(); //相同就打对勾
}
else
{
pCmdUI->SetCheck(0);
}
}
为什么要写成这样呢?因为我们每点击一次菜单,这个更新函数就会走我们菜单项那么多的次数。记录点击的ID,在和传进来的ID做比较,就能在刷新的时候设置好对勾的选项了。
如何在点击视图的时候右键弹出一个菜单?
首先在视图添加一个右键按下的消息,然后
第一种方法:
void CMenuView::OnRButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CMenu *menu = AfxGetMainWnd()->GetMenu()->GetSubMenu(0); //定义个menu的指针,获得当前框架菜单的第一个子菜单
ClientToScreen(&point); //更换传进来左边点的左边,做到跟踪弹出
menu->TrackPopupMenu(TPM_LEFTBUTTON|TPM_LEFTBUTTON,point.x,point.y,this); //让这个menu弹出一个menu,最后一个参数最好填框架类的指针
menu->Detach(); //分离菜单和资源
CView::OnRButtonDown(nFlags, point);
}
第二种方法:
void CMenuView::OnRButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
ClientToScreen(&point);
GetParent()->GetMenu()->GetSubMenu(0)->TrackPopupMenu(TPM_LEFTBUTTON|TPM_LEFTBUTTON,point.x,point.y,this);
CView::OnRButtonDown(nFlags, point);
}