CMFCMenuButton无法正确删除所有子菜单项的问题
菜单资源定义
IDR_MENU_POPUP_MANAGE_GROUPS MENU BEGIN POPUP "__MANAGE_GROUP__" BEGIN MENUITEM "Add Group", ID_POPUP_ADD_GROUP POPUP "Edit Group" BEGIN MENUITEM "__EDIT__", ID_POPUP_EDIT_GROUP_BASE END POPUP "Delete Group" BEGIN MENUITEM "__DELETE__", ID_POPUP_DELETE_GROUP_BASE END END END
问题描述
该菜单被CMFCMenuButton使用,运行时尝试动态删除子菜单的代码如下:
CMenu* pMenu = m_menuManageGroups.GetSubMenu(0); CMenu* pSubMenu = nullptr; pSubMenu = pMenu->GetSubMenu(1); pMenu->RemoveMenu(ID_POPUP_EDIT_GROUP_BASE, MF_BYCOMMAND);
第一次执行时Edit子菜单不再显示,看似有效。但后续向子菜单添加菜单项:
for (auto& groupInfo : mapGroups) { // first: Group Name // second: Group Id const auto iMenuItemId = iMenuBase + groupInfo.second; pSubMenu->AppendMenu(MF_STRING, iMenuItemId, groupInfo.first); }
新项成功显示后,再次执行删除代码,新的菜单项会追加到现有子菜单末尾。原本以为RemoveMenu会删除所有现有子菜单项,请问这是为什么?
原因分析与解决方法
核心误解:你没正确删除目标对象
你以为RemoveMenu会删除整个子菜单或清空所有项,但实际上你的代码只删除了弹出菜单内部的一个特定菜单项,且后续操作存在逻辑漏洞:
删除的是弹出菜单内部的菜单项,而非父菜单的弹出项
你的菜单结构中,__MANAGE_GROUP__的直接子项包括:Add Group(普通项)、Edit Group(弹出菜单)、Delete Group(弹出菜单)。你调用的pMenu->RemoveMenu(ID_POPUP_EDIT_GROUP_BASE, MF_BYCOMMAND),是在__MANAGE_GROUP__的子菜单中查找ID为ID_POPUP_EDIT_GROUP_BASE的项——但这个ID属于Edit Group弹出菜单内部的菜单项,不属于pMenu的直接子项。第一次执行后Edit子菜单消失,只是因为弹出菜单内部只剩这一个菜单项,删除后变为空,系统自动隐藏了父菜单里的弹出项,但父菜单的弹出项本身并未被删除。后续操作的是缓存的弹出菜单指针
你提前获取的pSubMenu指向Edit Group的弹出菜单对象,即使父菜单的弹出项被隐藏,这个对象依然存在。添加新项时是直接追加到该菜单末尾,没有清空原有内容,导致新项叠加。再次执行删除代码时目标项已不存在
第一次执行已经删掉了ID_POPUP_EDIT_GROUP_BASE的菜单项,后续再执行相同代码,RemoveMenu找不到匹配项,自然没有效果,新项会持续追加。
正确处理方式
方式1:彻底移除父菜单中的Edit Group弹出项
CMenu* pMenu = m_menuManageGroups.GetSubMenu(0); // 获取Edit Group弹出菜单指针 CMenu* pEditSubMenu = pMenu->GetSubMenu(1); // 清空弹出菜单内所有项 while (pEditSubMenu->GetMenuItemCount() > 0) { pEditSubMenu->RemoveMenu(0, MF_BYPOSITION); } // 删除父菜单中的Edit Group弹出项(用位置索引更可靠,因为POPUP项通常无显式ID) pMenu->RemoveMenu(1, MF_BYPOSITION);
方式2:仅清空弹出菜单内的所有项(保留父菜单弹出项)
如果只是想每次添加新项前清空旧内容,只需要执行清空逻辑:
CMenu* pMenu = m_menuManageGroups.GetSubMenu(0); CMenu* pEditSubMenu = pMenu->GetSubMenu(1); // 清空所有现有项 while (pEditSubMenu->GetMenuItemCount() > 0) { pEditSubMenu->RemoveMenu(0, MF_BYPOSITION); } // 再添加新项 for (auto& groupInfo : mapGroups) { const auto iMenuItemId = iMenuBase + groupInfo.second; pEditSubMenu->AppendMenu(MF_STRING, iMenuItemId, groupInfo.first); }
内容的提问来源于stack exchange,提问作者Andrew Truckle

