1 菜单栏选项的打勾,加粗,禁用
首先我们需要知道菜单栏包含子菜单栏,依次使用下标去区分。然后拿到子菜单栏后,就可以操作里面的选项了。可以通过下标,选项的ID(在资源视图的菜单栏的图,点击选项右击属性即可获取)进行操作。
代码:
由于为了减少视图的工作量,并且根据上一篇菜单栏的消息路由,框架也可以处理菜单栏的消息,所以代码放在框架类的OnCreate处理,注意,是操作菜单栏本身的选项时放在菜单栏处理,当处理菜单栏里面选项的左中右键按下时,尽量放在视图处理,否则框架可能无法捕获,但是菜单栏的变量需要重新定义,不要Get获取菜单栏,否则出错。
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("未能创建工具栏\n");
return -1; // 未能创建
}
if (!m_wndStatusBar.Create(this))
{
TRACE0("未能创建状态栏\n");
return -1; // 未能创建
}
m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT));
// TODO: 如果不需要可停靠工具栏,则删除这三行
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
//1 获取菜单栏
CMenu *menu = GetMenu();
//2 获取第一个子菜单栏,0代表下标
CMenu *submenu = menu->GetSubMenu(0);
//3 操作子菜单中的选项
//1) 添加勾勾
submenu->CheckMenuItem(0, MF_BYPOSITION | MF_CHECKED);//下标法
submenu->CheckMenuItem(ID_FILE_OPEN, MF_BYCOMMAND | MF_CHECKED);//ID法,需要去菜单栏拿取选项的ID并且参1改为命令宏,是对应使用的
//2)让选项加粗(设置默认项),注意一个菜单栏只能有一个加粗,所以最后3将覆盖2加粗
submenu->SetDefaultItem(2, TRUE);
submenu->SetDefaultItem(3, TRUE);
//3) 禁用选项,使选项变灰(注意分界线也算一个下标选项)
CFrameWnd::m_bAutoMenuEnable = false;//这句一般放构造处理
submenu->EnableMenuItem(5, MF_BYPOSITION | MF_DISABLED);
return 0;
}
结果可以看到,0,1打上勾。2被3覆盖加粗。4为分界线不需要处理。5被禁用了即打印。
2 菜单栏的移除与加载自定义的菜单栏
我们在上面的例子中继续添加代码即可。重复的代码可以不用看。
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("未能创建工具栏\n");
return -1; // 未能创建
}
if (!m_wndStatusBar.Create(this))
{
TRACE0("未能创建状态栏\n");
return -1; // 未能创建
}
m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT));
// TODO: 如果不需要可停靠工具栏,则删除这三行
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
//1 获取菜单栏
CMenu *menu = GetMenu();
//2 获取第一个子菜单栏,0代表下标
CMenu *submenu = menu->GetSubMenu(0);
//3 操作子菜单中的选项
//1) 添加勾勾
submenu->CheckMenuItem(0, MF_BYPOSITION | MF_CHECKED);//下标法
submenu->CheckMenuItem(ID_FILE_OPEN, MF_BYCOMMAND | MF_CHECKED);//ID法,需要去菜单栏拿取选项的ID并且参1改为命令宏,是对应使用的
//2)让选项加粗(设置默认项),注意一个菜单栏只能有一个加粗,所以最后3将覆盖2加粗
submenu->SetDefaultItem(2, TRUE);
submenu->SetDefaultItem(3, TRUE);
//3) 禁用选项,使选项变灰(注意分界线也算一个下标选项)
CFrameWnd::m_bAutoMenuEnable = false;//这句一般放构造处理
submenu->EnableMenuItem(5, MF_BYPOSITION | MF_DISABLED);
//移除菜单栏
SetMenu(NULL);
//重新加载自己新建的菜单栏(需要自己去菜单栏操作,右击Menu文件夹插入Menu即可)
CMenu menu2;
menu2.LoadMenuW(IDR_MENU1);
SetMenu(&menu2);
menu2.Detach();//防止窗口创建后menu2被释放,再按选项
return 0;
}
这是我自己自定义的菜单栏。
结果:
3 菜单栏的更新机制
菜单栏的选项类似Qt的绘图事件,都是会自动更新绘图,MFC的菜单栏也一样,每次按下某个选项后,都会自动更新菜单栏。因为菜单栏的更新机制是自动的,所以我们一般通过使用标志位来显示选项以达到自己的目的。例如下面案例,按下cc选项,使bb选项变亮。
继续上面的程序:
1)因为我们要使bb变亮,所以创建bb的UI处理程序。
2)又因为我们需要按下cc控制bb的亮度,所以需要添加消息的COMMAND回调函数。
3)添加成员变量标志位bool类型。
4)编写代码。
//bb的自动更新回调
void CMainFrame::OnUpdateBbBb(CCmdUI *pCmdUI)
{
// TODO: 在此添加命令更新用户界面处理程序代码
//自动回调更新,不需要手动调用
if (m_cc == true) {
pCmdUI->Enable(TRUE);
}
else {
pCmdUI->Enable(FALSE);
}
}
//cc的按钮按下回调
void CMainFrame::OnBbCc()
{
// TODO: 在此添加命令处理程序代码
//按下cc键
m_cc = !m_cc;//即m_cc = TRUE;
}
结果就是按下cc后,bb的亮度改变,不截图了。
4 左键弹出菜单栏快捷键
由于是鼠标按下事件,所以我们将函数放在视图中处理,放在框架会导致没反应。注意一下菜单栏的选项放在框架处理,选项的按下放在视图处理。
void CMenuView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//重新创建菜单栏,不要使用Get获取框架类的对象
//CMenu *m = GetMenu();//在视图而非框架类中时,禁用
CMenu menu;
menu.LoadMenuW(IDR_MENU1);
CMenu *submenu = menu.GetSubMenu(0);
ClientToScreen(&point);//将相对于屏幕的坐标换成相对于窗口的坐标
//按下左键,弹出子菜单栏,即左键就是该子菜单栏的快捷键
submenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON, point.x, point.y, this);
CView::OnLButtonDown(nFlags, point);
}
结果,按下左键就相当于按下了bb子菜单栏。