由AppendMenu()引发的错误

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

 最近一直看孙鑫的教程,有一节讲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中使用AppendMenu出现的错误。首先,我要回忆一下AppendMenu函数的基本用法以及常见的错误原因。AppendMenu是MFC中用于向菜单添加新项的成员函数,属于CMenu类。常见的错误可能包括参数传递不正确、资源未正确加载、或者菜单句柄无效等。 用户提供的引用内容中,引用[3]提到了MFC应用程序的开发流程,包括对话框的创建和控件的添加,这可能与菜单操作相关。虽然用户的问题是关于AppendMenu错误,但引用中没有直接提到菜单相关的问题,但可以推测用户可能在基于对话框的MFC程序中尝试动态添加菜单项,或者在框架窗口中使用菜单遇到了问题。 接下来,我需要考虑AppendMenu的参数是否正确。函数原型是BOOL AppendMenu(UINT nFlags, UINT_PTR nIDNewItem = 0, LPCTSTR lpszNewItem = NULL);。常见的错误可能包括: 1. **参数顺序错误**:例如,将菜单文本放在ID的位置,或者标志位不正确。 2. **未正确指定MF_STRING标志**:如果添加的是字符串菜单项,必须指定MF_STRING。 3. **使用错误的菜单句柄**:可能尝试在未正确获取菜单句柄的情况下调用AppendMenu,比如在框架窗口中没有获取主菜单,或者在弹出菜单中没有正确创建。 4. **资源ID冲突**:新添加的菜单项ID与现有ID重复,导致意外行为。 5. **未正确更新菜单**:添加菜单项后,可能需要调用DrawMenuBar来刷新显示。 另外,用户可能在动态创建菜单,没有正确处理弹出菜单(使用MF_POPUP),或者在子菜单处理上有误。例如,当添加子菜单,需要先创建一个CMenu对象,然后将其附加到父菜单,这AppendMenu的参数应使用MF_POPUP,并传递子菜单的句柄。 还需要检查是否有未加载的菜单资源,或者是否在正确的机调用AppendMenu。例如,在框架窗口的OnCreate函数中,或者在响应某个消息动态添加菜单项。 根据常见的错误情况,解决方案应包括检查参数是否正确,确保菜单句柄有效,处理资源ID,以及更新菜单显示。此外,还需要考虑Unicode和多字节字符集的问题,即是否使用_T()宏包裹字符串,或者是否因字符集设置导致字符串转换错误。 另外,引用中提到的错误示例,如链接错误(LNK2001)可能不直接相关,但用户可能是在编译或链接阶段遇到问题,比如未正确链接MFC库,但根据用户的问题描述,更可能是在运行或设计的逻辑错误,而非编译错误。 总结可能的解决方案步骤: 1. **确认菜单句柄有效性**:确保获取到了正确的菜单对象,比如在框架窗口中使用GetMenu()获取主菜单,或正确创建了CMenu对象。 2. **检查参数顺序和标志**:确认nFlags是否正确,如MF_STRING,MF_SEPARATOR等,并确保ID不冲突。 3. **字符串处理**:使用_T()宏或CString来传递菜单文本,避免字符集问题。 4. **子菜单处理**:若添加子菜单,需创建CMenu对象,使用AppendMenu(MF_POPUP, subMenu.m_hMenu, _T("子菜单")),并确保子菜单对象在作用域内有效。 5. **更新菜单显示**:添加后调用CWnd::DrawMenuBar()刷新显示。 6. **错误处理**:检查AppendMenu的返回值,若为FALSE,调用GetLastError()获取错误代码。 例如,用户可能在对话框程序中尝试添加菜单,但对话框默认没有菜单栏,需要先通过资源编辑器添加菜单资源,或者在代码中创建。若用户未正确创建菜单资源,直接调用AppendMenu可能导致失败。 另外,检查是否在正确的消息处理阶段添加菜单项,例如在WM_INITMENU或WM_CREATE消息处理中。 可能用户的问题代码中缺少了某些步骤,比如没有获取主菜单,或者错误地使用了局部CMenu对象导致句柄失效。 现在,根据这些思路,整理出解决方案的步骤,并参考用户提供的引用中的MFC开发流程,特别是引用[3]中提到的控件添加和消息处理,可能需要确保菜单操作在正确的初始化阶段完成,并且正确处理消息响应。</think>在MFC中使用`AppendMenu`函数出现错误的常见原因及解决方案如下: --- ### **1. 参数顺序与标志位错误** - **问题**:`AppendMenu`的参数顺序为`nFlags`(标志位)、`nIDNewItem`(菜单项ID或弹出菜单句柄)、`lpszNewItem`(显示文本)。 - **正确用法**: ```cpp pMenu->AppendMenu(MF_STRING, ID_MENU_ITEM, _T("新菜单项")); ``` 若添加分隔符: ```cpp pMenu->AppendMenu(MF_SEPARATOR); ``` - **注意**:必须明确指定`MF_STRING`或`MF_SEPARATOR`等标志[^3]。 --- ### **2. 菜单句柄未正确获取** - **问题**:未获取有效的菜单对象。 - **解决方案**: - **主菜单**:在框架窗口中使用`GetMenu()`获取主菜单: ```cpp CMenu* pMainMenu = GetMenu(); // 框架窗口中 CMenu* pSubMenu = pMainMenu->GetSubMenu(0); // 获取第一个子菜单 ``` - **动态创建菜单**:若为弹出菜单,需先创建`CMenu`对象并保留作用域: ```cpp CMenu popupMenu; popupMenu.CreatePopupMenu(); popupMenu.AppendMenu(MF_STRING, ID_ITEM, _T("弹出项")); ``` 附加到父菜单: ```cpp pMainMenu->AppendMenu(MF_POPUP, (UINT_PTR)popupMenu.m_hMenu, _T("子菜单")); ``` --- ### **3. 未刷新菜单显示** - **问题**:动态修改菜单后未刷新界面。 - **解决方案**:调用`DrawMenuBar()`更新显示: ```cpp GetParentFrame()->DrawMenuBar(); // 框架窗口中 ``` --- ### **4. 资源ID冲突** - **问题**:菜单项ID与现有ID重复。 - **检查方法**:在资源文件(`.rc`)中确认所有ID唯一性,或使用`#define`定义新ID。 --- ### **5. Unicode与多字节字符集问题** - **问题**:未使用`_T()`宏或`CString`导致字符串转换错误。 - **解决方案**: ```cpp pMenu->AppendMenu(MF_STRING, ID_ITEM, _T("中文菜单项")); // 使用_T包裹 ``` --- ### **6. 错误处理** - **调试方法**:检查`AppendMenu`返回值,若为`FALSE`,调用`GetLastError()`获取错误码: ```cpp if (!pMenu->AppendMenu(...)) { DWORD err = GetLastError(); TRACE("AppendMenu失败,错误码:%d\n", err); } ``` --- ### **示例代码(对话框动态添加菜单)** ```cpp // 在对话框初始化函数中 CMenu mnuMain; mnuMain.CreateMenu(); CMenu mnuSub; mnuSub.CreatePopupMenu(); mnuSub.AppendMenu(MF_STRING, 1001, _T("新增项")); mnuMain.AppendMenu(MF_POPUP, (UINT_PTR)mnuSub.m_hMenu, _T("操作")); SetMenu(&mnuMain); mnuMain.Detach(); // 防止对象销毁菜单被删除 ``` ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值