VC下动态改变菜单显示的标题和Checked状态(Change title of CMenu and Checked)

曾经为这个一度苦闷,终于有一天找到了...估计不是最合理的办法
使用ModifyMenu函数,原型如下:
  1. /***************************************************
  2.  * 4个参数:
  3.  * nPosition       - 旧菜单的资源ID或位置(根据nFlags取值)
  4.  * nFlags           - MF_BYCOMMAND or MF_BYPOSITION 前者用资源ID标识,后者用位置标识
  5.  * nIDNewItem  - 设置菜单为新的资源ID或新的位置(根据nFlags取值)
  6.  * lpszNewItem - 菜单所显示字符串
  7.  ***************************************************/
  8. BOOL ModifyMenu( UINT nPosition, UINT nFlags,
  9.         UINT nIDNewItem = 0, LPCTSTR lpszNewItem = NULL );

href="http://www.j2megame.org/wupei/plugins/plogeshi/styles/plogeshi.css" type="text/css" rel="stylesheet" />演示代码:

  1. //鼠标右键单击弹出选单
  2. CMenu menu;
  3. menu.LoadMenu(IDR_MY_MENU); //载入事先定义的选单
  4. CMenu* pMenu=menu.GetSubMenu(0);
  5.  
  6. if(m_isShow)
  7. {
  8.         pMenu->ModifyMenu(
  9.                 ID_MENUITEM_ONE,
  10.                 MF_BYCOMMAND,
  11.                 ID_MENUITEM_ONE,
  12.                 "第一个标题"
  13.         );
  14. }
  15. else
  16. {
  17.         pMenu->ModifyMenu(
  18.                 ID_MENUITEM_ONE,
  19.                 MF_BYCOMMAND,
  20.                 ID_MENUITEM_ONE,
  21.                 "第二个标题"
  22.         );
  23. }
  24.  
  25. CPoint pos;
  26. GetCursorPos(&pos);     //获取当前鼠标位置(相对全屏幕位置)
  27. pMenu->TrackPopupMenu(  //弹出菜单
  28.         TPM_LEFTALIGN|TPM_RIGHTBUTTON,
  29.         pos.x,pos.y,
  30.         AfxGetMainWnd()
  31. );

动态改变菜单Checked状态

  1. //原型
  2. /***************************************************
  3.  * 2个参数:
  4.  * nIDCheckItem - 菜单资源ID或位置
  5.  * nCheck  - MF_BYCOMMAND,MF_BYPOSITION,MF_CHECKED,MF_UNCHECKED
  6.  * Return Value:The previous state of the item: MF_CHECKED or MF_UNCHECKED,
  7.                         or 0xFFFFFFFF if the menu item did not exist.
  8.  ***************************************************/
  9. UINT CheckMenuItem( UINT nIDCheckItem, UINT nCheck );

演示:

  1. CMenu* secondMenu = pMenu->GetSubMenu(0);
  2. secondMenu->CheckMenuItem(ID_MENUITEM_AUTOCLOSE,MF_UNCHECKED); //改变为无对勾状态
 
//所有的菜单(包括顶层框架菜单与弹出式菜单)项均会触发OnInitMenu函数,分以下几种情况: // 一 顶层框架菜单:就是文件,编辑等这种菜单,框架菜单在主窗口显示后并不会自动调用OnInitMenu函数, // 必须手动设置框架菜单的自绘标志,否则在主窗口显示后框架菜单仍然为非自绘状态 // 二 系统菜单:这种情况比较特殊,需要注意,分以下几种情况: // (1) 主窗口显示时在标题栏上点右键弹出的菜单,此时进入到OnInitMenu函数中后,通过遍历发现 // 这些菜单项仍然是框架菜单项,也就是文件,编辑等,而不是最小化,最大化等系统菜单。 // (2) 主窗口未最小化时(不管主窗口是前台窗口还是非前台窗口),在任务栏的程序按钮上点右键弹出的菜单, // 此时进入到OnInitMenu函数中后,通过遍历发现这些菜单项仍然是框架菜单项,也就是文件,编辑等,而不是最小化,最大化等系统菜单。 // (3) 主窗口最化小时,在任务栏的程序按钮上点右键弹出的菜单,此时进入到OnInitMenu函数中后,发现该菜单才是系统菜单,最小化,最大化等。 // 三 弹出式菜单:所有弹出式菜单都会触发OnInitMenu函数处理 //因为框架菜单已经在OnInitMenu函数之前进行了强制设置自绘标志,所以这里不再考虑是否将框架菜单进行过滤掉,当进入到ModifyMenuStyle函数中后,会发现该 //菜单已经设置了自绘标志,就不再处理了。 //这里只判断是否系统菜单,并对其进行过滤,不自绘系统菜单
<think> 我们正在讨论的是如何在Visual C++ (VC)中去掉CMenu菜单项的CHECKED状态CMenu类是MFC中用于操作菜单的类。要修改菜单项的状态,我们可以使用CheckMenuItem函数。 该函数的原型如下: UINT CheckMenuItem( UINT nIDCheckItem, UINT nCheck ); 其中: nIDCheckItem:指定要修改的菜单项,可以通过其命令ID或者位置(position)指定。 nCheck:指定如何设置菜单项的状态,以及如何确定nIDCheckItem参数(是通过命令ID还是位置)。通常,我们需要指定MF_BYCOMMAND(表示通过命令ID)或MF_BYPOSITION(表示通过位置),以及MF_CHECKED(选中)或MF_UNCHECKED(未选中)。 因此,要去掉菜单项的选中状态(即设置为未选中),我们可以这样调用: pMenu->CheckMenuItem(nID, MF_BYCOMMAND | MF_UNCHECKED); 或者如果通过位置指定: pMenu->CheckMenuItem(nPosition, MF_BYPOSITION | MF_UNCHECKED); 注意:我们需要获取指向CMenu对象的指针。如果我们要修改的是顶层菜单(比如“文件”菜单)下的某个子菜单项,我们可能需要先获取顶层菜单,然后获取子菜单(通过GetSubMenu函数),然后再修改子菜单中的项。 例如,假设我们有一个顶层菜单栏(CMenu对象)m_menuBar,其中第一个菜单(位置0)是“编辑”菜单,它是一个弹出菜单(子菜单)。我们想要移除该子菜单中ID为ID_EDIT_COPY的项的选中状态,可以这样做: CMenu* pSubMenu = m_menuBar.GetSubMenu(0); // 获取第一个弹出菜单(即“编辑”菜单) if (pSubMenu) { pSubMenu->CheckMenuItem(ID_EDIT_COPY, MF_BYCOMMAND | MF_UNCHECKED); } 另外,如果菜单项是动态创建的,或者我们在其他时间(比如点击菜单项时)需要修改状态,我们也可以使用相同的函数。 需要注意的是,当我们修改了菜单项的状态后,有时需要强制重绘菜单栏(如果菜单当前没有显示,则不需要立即重绘)。如果菜单当前是显示的(比如下拉菜单打开时),修改状态后会自动更新。如果是修改菜单栏上的项,可能需要调用CWnd::DrawMenuBar来重绘菜单栏。 例如,如果修改的是顶层菜单栏上的一个项(注意:顶层菜单栏上的项通常是弹出菜单,不能单独设置选中状态,因为它们总是弹出子菜单,所以通常我们修改的是下拉菜单中的项),或者修改后需要立即更新显示,我们可以这样: // 假设m_menuBar已经附加到主框架窗口 AfxGetMainWnd()->DrawMenuBar(); 但是,如果我们修改的是下拉菜单中的项,并且下拉菜单当前没有打开,那么我们只需要在下次打开时看到更新,所以不需要立即重绘。 总结步骤: 1. 获取要修改的菜单项所在的CMenu对象(可能是子菜单)。 2. 调用CheckMenuItem函数,指定菜单项的标识(ID或位置)MF_UNCHECKED标志(同时指定MF_BYCOMMAND或MF_BYPOSITION)。 3. 如果修改的是菜单栏上的项(即顶层菜单项,但实际上顶层菜单项一般不会设置选中标记,因为它们是弹出菜单),或者需要立即更新菜单栏的显示,则调用DrawMenuBar重绘菜单栏。 示例代码: // 假设我们有一个菜单项ID_MY_ITEM,我们要去掉它的选中状态 CMenu* pMenu = AfxGetMainWnd()->GetMenu(); // 获取主窗口的菜单栏 if (pMenu) { // 假设我们要修改的菜单项在第一个子菜单CMenu* pSubMenu = pMenu->GetSubMenu(0); // 第一个子菜单 if (pSubMenu) { pSubMenu->CheckMenuItem(ID_MY_ITEM, MF_BYCOMMAND | MF_UNCHECKED); // 如果需要,更新菜单栏(因为修改的是子菜单,所以通常不需要立即更新菜单栏,但如果你希望立即更新显示,可以调用DrawMenuBar) AfxGetMainWnd()->DrawMenuBar(); } } 但是,如果我们知道要修改的菜单项在哪个子菜单中,直接获取该子菜单然后修改即可。 另外,有时候我们可能通过类向导为菜单项添加了UPDATE_COMMAND_UI处理函数,那么在该函数中,我们可以通过CCmdUI对象来设置选中状态。例如: void CMyView::OnUpdateMyMenuItem(CCmdUI* pCmdUI) { // 根据条件设置是否选中 pCmdUI->SetCheck(FALSE); // 设置为未选中 } 这种方法更为常用,因为MFC框架会在菜单弹出前自动调用更新处理函数来设置菜单项的状态(包括选中状态、启用状态等)。因此,我们通常建议使用UPDATE_COMMAND_UI机制来管理菜单项的状态。 所以,如果我们的目的是根据某个条件去掉菜单项的选中状态,最好在UPDATE_COMMAND_UI处理函数中调用SetCheck(FALSE)。 结论: 有两种方法: 方法一:使用CheckMenuItem函数直接设置。 方法二:在UPDATE_COMMAND_UI处理函数中使用CCmdUI::SetCheck(FALSE)。 根据情况选择: - 如果是在需要立即改变菜单状态的时候(比如响应某个命令),使用方法一。 - 如果是根据程序状态动态改变菜单状态,使用方法二(推荐)。 下面我们将分别给出两种方法的示例。 方法一示例(直接设置): // 假设在某个命令处理函数中 void CMyFrame::OnUncheckMyItem() { CMenu* pMenu = GetMenu(); // 获取主菜单栏 if (pMenu) { CMenu* pSubMenu = pMenu->GetSubMenu(0); // 假设目标菜单项在第一个子菜单中 if (pSubMenu) { pSubMenu->CheckMenuItem(ID_MY_ITEM, MF_BYCOMMAND | MF_UNCHECKED); // 如果需要,更新菜单栏(如果修改的是当前显示菜单栏) DrawMenuBar(); // CFrameWnd的成员函数 } } } 方法二示例(使用UPDATE_COMMAND_UI): // 在头文件中声明 afx_msg void OnUpdateMyMenuItem(CCmdUI* pCmdUI); // 在消息映射中添加 ON_UPDATE_COMMAND_UI(ID_MY_ITEM, OnUpdateMyMenuItem) // 实现 void CMyFrame::OnUpdateMyMenuItem(CCmdUI* pCmdUI) { // 假设我们有一个成员变量m_bChecked,用于控制是否选中 // 我们想要去掉选中状态,所以设置为FALSE pCmdUI->SetCheck(FALSE); // 无论之前是什么状态,现在设置为未选中 // 或者根据条件设置 // if (condition) pCmdUI->SetCheck(FALSE); // else pCmdUI->SetCheck(TRUE); } 注意:使用方法二时,MFC框架会在菜单弹出前自动调用这个更新处理函数来更新菜单项的状态。 因此,根据实际需求选择合适的方法。 </think> 在 Visual C++ (MFC) 中移除 `CMenu` 菜单项的选中状态CHECKED),可通过以下两种方法实现: --- ### 方法一:使用 `CheckMenuItem()` 函数(直接操作) ```cpp // 获取主菜单CMenu* pMenu = GetMenu(); // 获取子菜单(例如"文件"菜单位置0) CMenu* pSubMenu = pMenu->GetSubMenu(0); // 移除ID为ID_MY_ITEM的菜单项选中状态 pSubMenu->CheckMenuItem(ID_MY_ITEM, MF_BYCOMMAND | MF_UNCHECKED); ``` - **关键参数**: - `MF_BYCOMMAND`:按命令ID标识菜单项(也可用 `MF_BYPOSITION` 按位置标识) - `MF_UNCHECKED`:清除选中状态 - **更新显示**:若菜单栏已打开,需调用 `DrawMenuBar()` 刷新: ```cpp DrawMenuBar(); // 重绘菜单栏 ``` --- ### 方法二:使用 `UPDATE_COMMAND_UI` 机制(推荐) 通过 MFC 的消息映射自动管理状态: 1. **声明消息处理函数**(头文件): ```cpp afx_msg void OnUpdateMyMenuItem(CCmdUI* pCmdUI); ``` 2. **添加消息映射**(源文件): ```cpp BEGIN_MESSAGE_MAP(CMyFrame, CFrameWnd) ON_UPDATE_COMMAND_UI(ID_MY_ITEM, OnUpdateMyMenuItem) END_MESSAGE_MAP() ``` 3. **实现状态控制**: ```cpp void CMyFrame::OnUpdateMyMenuItem(CCmdUI* pCmdUI) { // 设置未选中状态 pCmdUI->SetCheck(FALSE); // 若需条件控制:pCmdUI->SetCheck(m_bIsChecked ? 1 : 0); } ``` - **优势**:自动在菜单弹出前更新状态,无需手动刷新界面[^1]。 --- ### 注意事项 1. **菜单层级**:若操作子菜单项,需先通过 `GetSubMenu()` 获取子菜单对象。 2. **动态菜单**:对动态创建的菜单(如右键菜单),需在 `OnInitMenuPopup()` 中处理状态。 3. **状态同步**:使用 `UPDATE_COMMAND_UI` 可确保状态与程序数据一致。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值