由AppendMenu()引发的错误

本文探讨了在MFC应用程序中动态添加菜单项的方法。通过分析不同实现方式及其遇到的问题,如局部变量引起的错误和菜单刷新问题,最终找到了有效的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 最近一直看孙鑫的教程,有一节讲appendmenu(),看完 便自己动手延展了一下。                                      

             本想是在上下文菜单里为名叫“append”的菜单项添加一个消息响应,目的是为了在主菜单动态地添加一个popup菜单。

             用classwizard在视类中添加了相应的响应函数:

void CMenuView::OnMENUappend()
 { 
// TODO: Add your command handler code here 
CMenu menu1; 
menu1.CreateMenu(); 
GetMenu()->AppendMenu(MF_POPUP,(UINT)menu1.m_hMenu,"menubyappend"); 
menu1.Detach();
}
运行->右键->append . . .  出错

     

        一看到这个脑袋就大了。思索了一下,我以为是局部变量menu1的“局部”问题, 但是我想后面不是有Detach()吗? 问了某位网友,说是将menu1作为类的变量,虽然有疑惑,但还是照做了。  果然,还是错误。。

       为啥在CMainFrame的Oncreate()中响应不会出现错误呢?我开始想,是不是因为context菜单是属于视类的,而主菜单是属于框架类的。而在视类中不能用这种方法来做本是框架类该做的事。 所以我将视类中的OnMENUappend()移到框架类中, 右键append 果然没有出错, 但是主菜单中还是没有我要的menubyappend 。

     于是我换了一种方式,在视类中又加了OnMENUappend(),不过将代码改了:

void CMenuView::OnMENUappend()
 { 
// TODO: Add your command handler code here 
CMenu menu1; 
menu1.CreateMenu(); 
GetpParent()->GetMenu()->AppendMenu(MF_POPUP,(UINT)menu1.m_hMenu,"menubyappend"); 
GetParent()->DrawMenuBar();
menu1.Detach();
 }

       额,其中的DrawMenuBar()是为了解决主菜单不能及时刷新的问题。

       运行,append。   裸然出现了我所要的菜单项:


      但是,之前我把视类的响应函数移到框架时,为什么不起作用呢?难道是消息路由顺序的缘故吗? 

       于是百度了一下顺序:CMyView--->CMyDoc-->CMultiDocTemplate(它通常不会处理)-->CMyChildFrame-->CMyApp->CMyFrameWnd

       可见,最后还是会将消息路由给框架类的。但我的框架类中的似乎并没有相应OnMENUappend()。  百思不得其解。明天来解决吧。真的要睡了。







<think>我们讨论的是如何判断MFC中通过menuPopup.AppendMenu添加的菜单项是否处于check状态。 在MFC中,菜单项的状态(包括checked状态)可以通过CMenu类的GetMenuState函数来获取。 具体步骤如下: 1. 获取菜单项的ID。 2. 使用CMenu::GetMenuState函数,传入菜单项的ID和MF_BYCOMMAND标志,来获取该菜单项的状态。 3. 检查返回的状态是否包含MF_CHECKED标志。 注意:如果菜单项是通过位置索引(而不是命令ID)添加的,则可以使用MF_BYPOSITION标志。 示例代码: 假设我们有一个弹出菜单对象menuPopup,并且我们通过AppendMenu添加了一些菜单项,其中有一个菜单项的ID为ID_MENU_ITEM1。 在需要判断的地方,我们可以这样写: ```cpp CMenu menuPopup; menuPopup.CreatePopupMenu(); // 添加菜单项,并设置checked状态(这里只是示例,实际可能根据条件设置) menuPopup.AppendMenu(MF_STRING | MF_CHECKED, ID_MENU_ITEM1, _T("菜单项1")); // ... 其他代码 // 判断菜单项是否被选中 UINT nState = menuPopup.GetMenuState(ID_MENU_ITEM1, MF_BYCOMMAND); if (nState != 0xFFFFFFFF) // 检查菜单项是否存在 { if (nState & MF_CHECKED) { // 菜单项处于选中状态 TRACE(_T("菜单项被选中\n")); } else { // 菜单项未选中 TRACE(_T("菜单项未选中\n")); } } ``` 注意事项: 1. 如果菜单项不存在,GetMenuState返回0xFFFFFFFF(即-1)。 2. 除了MF_CHECKED,还可以检查其他状态,如MF_GRAYED(禁用)、MF_ENABLED(启用)等。 另外,如果菜单项是通过位置索引来访问的,可以这样: ```cpp // 假设要检查第一个菜单项(索引0) UINT nState = menuPopup.GetMenuState(0, MF_BYPOSITION); // 然后同样检查MF_CHECKED ``` 但是,通常我们使用命令ID(MF_BYCOMMAND)来获取状态,因为这样更直接,而且菜单项的位置可能会变化。 所以,总结一下:使用CMenu::GetMenuState函数,并检查返回的状态中是否包含MF_CHECKED标志。 如果菜单项是动态的,并且我们不确定其ID,那么我们需要遍历菜单项。例如: ```cpp int nCount = menuPopup.GetMenuItemCount(); for (int i = 0; i < nCount; i++) { UINT nID = menuPopup.GetMenuItemID(i); if (nID != -1) // 不是分隔符 { UINT nState = menuPopup.GetMenuState(nID, MF_BYCOMMAND); // 或者直接通过位置:UINT nState = menuPopup.GetMenuState(i, MF_BYPOSITION); if (nState & MF_CHECKED) { // 这个菜单项被选中 } } } ``` 注意:分隔符的菜单项ID为-1。 因此,根据你的具体情况,选择使用命令ID还是位置索引来获取菜单项状态。 引用:在MFC中,CMenu类封装了菜单操作,GetMenuState是常用的获取菜单项状态的方法[^1]。</think>在 MFC 中判断弹出菜单项是否处于选中(check)状态,可以通过 `CMenu::GetMenuState()` 方法实现。以下是详细步骤和示例代码: ### 判断菜单项选中状态的方法 ```cpp // 获取菜单项状态 UINT nState = menuPopup.GetMenuState(nID, MF_BYCOMMAND); // 判断是否选中 if (nState & MF_CHECKED) { // 菜单项已选中 TRACE(_T("菜单项 %d 处于选中状态\n"), nID); } else { // 菜单项未选中 TRACE(_T("菜单项 %d 未选中\n"), nID); } ``` ### 完整使用示例 ```cpp // 创建弹出菜单 CMenu menuPopup; menuPopup.CreatePopupMenu(); // 添加菜单项(带选中状态) UINT nID1 = 1001; menuPopup.AppendMenu(MF_STRING | MF_CHECKED, nID1, _T("选中项")); // 添加未选中菜单项 UINT nID2 = 1002; menuPopup.AppendMenu(MF_STRING, nID2, _T("未选中项")); // 检查第一个菜单项状态 UINT state1 = menuPopup.GetMenuState(nID1, MF_BYCOMMAND); if (state1 != 0xFFFFFFFF && (state1 & MF_CHECKED)) { AfxMessageBox(_T("菜单项1处于选中状态")); } // 检查第二个菜单项状态 UINT state2 = menuPopup.GetMenuState(nID2, MF_BYCOMMAND); if (state2 != 0xFFFFFFFF && !(state2 & MF_CHECKED)) { AfxMessageBox(_T("菜单项2未选中")); } // 显示菜单 CPoint pt; GetCursorPos(&pt); menuPopup.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, this); ``` ### 关键点说明 1. **`GetMenuState()` 方法** - 第一个参数:菜单项 ID(使用 `MF_BYCOMMAND` )或位置索引(使用 `MF_BYPOSITION` ) - 返回值:包含状态标志的位掩码(`MF_CHECKED`, `MF_GRAYED` 等)[^1] 2. **状态标志说明**: ```cpp MF_CHECKED // 菜单项有选中标记 (✓) MF_UNCHECKED // 菜单项无选中标记 MF_GRAYED // 菜单项禁用(灰色) MF_DISABLED // 菜单项禁用 MF_ENABLED // 菜单项启用 ``` 3. **错误处理**: - 当菜单项不存在,`GetMenuState()` 返回 `0xFFFFFFFF` - 应先检查返回值有效性: ```cpp if (nState != 0xFFFFFFFF) { // 有效状态处理 } ``` ### 动态管理菜单状态 要修改菜单项选中状态,使用: ```cpp // 设置选中状态 menuPopup.CheckMenuItem(nID, MF_BYCOMMAND | MF_CHECKED); // 取消选中状态 menuPopup.CheckMenuItem(nID, MF_BYCOMMAND | MF_UNCHECKED); ``` ### 遍历所有菜单项 ```cpp int nCount = menuPopup.GetMenuItemCount(); for (int i = 0; i < nCount; i++) { UINT nID = menuPopup.GetMenuItemID(i); if (nID != -1) { // 排除分隔符 UINT state = menuPopup.GetMenuState(i, MF_BYPOSITION); if (state & MF_CHECKED) { TRACE(_T("位置 %d 的菜单项处于选中状态\n"), i); } } } ``` > 此方法适用于所有通过 `CMenu::AppendMenu()` 添加的菜单项,包括弹出菜单和主菜单栏[^1]。在实际应用中,建议将菜单状态管理封装到单独的类中,便于状态维护和更新。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值