从 App 主菜单栏中的 POPUP 菜单工具栏按钮调用时,OnInitMenuPopup 无法正确初始化
OnInitMenuPopup does not init correctly when called from a toolbar button that was a POPUP menu in the App main menu bar
长话短说,假设我的主菜单是一个 CMFCMenuBar 菜单定义如下:
IDR_MAINFRAME MENU
BEGIN
POPUP "&File"
BEGIN
MENUITEM "New", ID_FILE_NEW
MENUITEM "Open", ID_FILE_OPEN
MENUITEM "Save", ID_FILE_SAVE
POPUP "Save As"
BEGIN
MENUITEM "Format XXX", ID_FILE_SAVEAS_XXX
MENUITEM SEPARATOR
MENUITEM "Format YYY", ID_FILE_SAVEAS_YYY
MENUITEM SEPARATOR
MENUITEM "Format ZZZ", ID_FILE_SAVEAS_ZZZ
MENUITEM "Format WWW", ID_FILE_SAVEAS_WWW
END
MENUITEM "Close", ID_FILE_CLOSE
END
POPUP "&Object"
BEGIN
POPUP "Create object"
BEGIN
MENUITEM "Create object...", ID_CREATE_OBJECT
MENUITEM "Create object as...", ID_CREATE_OBJECTAS
END
POPUP "Save object"
BEGIN
MENUITEM "Save object...", ID_SAVE_AS_XXX
MENUITEM "Save object copy", ID_SAVE_OBJECT_COPY
END
END
MENUITEM "Delete", ID_DELETE_OBJECT
END
END
由于 POPUP 菜单没有 ID(它们的值都是 -1),为了知道我在哪个菜单上进行初始化,我按照 上的方法实现了 [=16] 之类的功能=]
bool CMainFrame::IsFileMenu(CMenu* pPopupMenu) const
{
if(!pPopupMenu);
return false;
return (pPopupMenu->GetMenuItemCount() > 0) && (pPopupMenu->GetMenuItemID(0) == ID_FILE_NEW);
}
bool CMainFrame::IsObjectMenu(CMenu* pPopupMenu) const
{
if(!pPopupMenu);
return false;
return (pPopupMenu->GetMenuItemCount() > 0) && (pPopupMenu->GetMenuItemID(2) == ID_DELETE_OBJECT);
}
菜单初始化如下:
void CMainFrame::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu)
{
if(!license.supports("SaveAsFile"))
{
if(IsFileMenu())
{
//code to find ID_FILE_SAVEAS_XXX parent menu ("Save As"), then recursively delete all its descendants and itself
}
if(IsObjectMenu())
{
for(int i = 0; i < pPopupMenu->GetMenuItemCount();i++)
{
MENUITEMINFO MenuItemInfo;
memset(&MenuItemInfo, 0, sizeof(MENUITEMINFO));
MenuItemInfo.cbSize = sizeof (MENUITEMINFO); // must fill up this field
MenuItemInfo.fMask = MIIM_SUBMENU;
if (!pPopupMenu->GetMenuItemInfo(i, &MenuItemInfo, TRUE))
continue;
CMenu* SubMenu = pPopupMenu->GetSubMenu(i);
if (SubMenu != NULL)
{
memset(&MenuItemInfo, 0, sizeof(MENUITEMINFO));
MenuItemInfo.cbSize = sizeof (MENUITEMINFO);
MenuItemInfo.fMask = MIIM_ID | MIIM_TYPE;
for(int j=0; j<SubMenu->GetMenuItemCount() ;j++ )
{
SubMenu->GetMenuItemInfo(j, &MenuItemInfo, TRUE);
if (MenuItemInfo.wID == ID_CREATE_OBJECTAS)
{
for (int i=0; i<m_custom_objects.GetSize(); i++)
pPopup->AppendMenu(MF_STRING | MF_ENABLED, WM_MENU_CUSTOM_OBJECTS_BEGIN + i, (LPCTSTR) m_custom_objects[i].GetName() );
found= true;
break;
}
}
if(found)
break;
}
}
}
}
__super::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);
}
注意 ID_FILE_SAVEAS_XXX
MENUITEM 标识符重复了!由于我不想在支持 "SaveAsFile" 的许可证不存在时删除 "Save Object" POPUP,因此绝对需要确定现在正在处理的菜单。
现在用户已经使用 MFC 自定义对话框创建了一个工具栏,然后他将 "Create Object" POPUP 拖到新的工具栏。当他单击工具栏的这个新按钮时,他会看到 "Create object" 和 "Create object as" 选项,但并不是因为 IsObjectMenu()
条件不满足而未附加自定义对象。当他来自主菜单时,行为完全不同;附加已完成!
当用户单击工具栏的按钮时,我如何编写代码以完成自定义对象的追加?
我并不为自己的代码感到骄傲,但我通过将"Object"的代码与"Create Object"菜单分开来解决了它。
bool CMainFrame::IsCreateObjectMenu(CMenu* pPopupMenu) const
{
if(!pPopupMenu);
return false;
return (pPopupMenu->GetMenuItemCount() > 0) && (pPopupMenu->GetMenuItemID(0) == ID_CREATE_OBJECT);
}
void CMainFrame::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu)
{
if(!license.supports("SaveAsFile"))
{
if(IsFileMenu())
{
//code to find ID_FILE_SAVEAS_XXX parent menu ("Save As"), then recursively delete all its descendants and itself
}
if(IsObjectMenu())
{
// Do things
}
if(IsCreateObjectMenu())
{
for (int i=0; i<m_custom_objects.GetSize(); i++)
pPopupMenu->AppendMenu(MF_STRING | MF_ENABLED, WM_MENU_CUSTOM_OBJECTS_BEGIN + i, (LPCTSTR) m_custom_objects[i].GetName());
}
}
__super::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);
}
长话短说,假设我的主菜单是一个 CMFCMenuBar 菜单定义如下:
IDR_MAINFRAME MENU
BEGIN
POPUP "&File"
BEGIN
MENUITEM "New", ID_FILE_NEW
MENUITEM "Open", ID_FILE_OPEN
MENUITEM "Save", ID_FILE_SAVE
POPUP "Save As"
BEGIN
MENUITEM "Format XXX", ID_FILE_SAVEAS_XXX
MENUITEM SEPARATOR
MENUITEM "Format YYY", ID_FILE_SAVEAS_YYY
MENUITEM SEPARATOR
MENUITEM "Format ZZZ", ID_FILE_SAVEAS_ZZZ
MENUITEM "Format WWW", ID_FILE_SAVEAS_WWW
END
MENUITEM "Close", ID_FILE_CLOSE
END
POPUP "&Object"
BEGIN
POPUP "Create object"
BEGIN
MENUITEM "Create object...", ID_CREATE_OBJECT
MENUITEM "Create object as...", ID_CREATE_OBJECTAS
END
POPUP "Save object"
BEGIN
MENUITEM "Save object...", ID_SAVE_AS_XXX
MENUITEM "Save object copy", ID_SAVE_OBJECT_COPY
END
END
MENUITEM "Delete", ID_DELETE_OBJECT
END
END
由于 POPUP 菜单没有 ID(它们的值都是 -1),为了知道我在哪个菜单上进行初始化,我按照 上的方法实现了 [=16] 之类的功能=]
bool CMainFrame::IsFileMenu(CMenu* pPopupMenu) const
{
if(!pPopupMenu);
return false;
return (pPopupMenu->GetMenuItemCount() > 0) && (pPopupMenu->GetMenuItemID(0) == ID_FILE_NEW);
}
bool CMainFrame::IsObjectMenu(CMenu* pPopupMenu) const
{
if(!pPopupMenu);
return false;
return (pPopupMenu->GetMenuItemCount() > 0) && (pPopupMenu->GetMenuItemID(2) == ID_DELETE_OBJECT);
}
菜单初始化如下:
void CMainFrame::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu)
{
if(!license.supports("SaveAsFile"))
{
if(IsFileMenu())
{
//code to find ID_FILE_SAVEAS_XXX parent menu ("Save As"), then recursively delete all its descendants and itself
}
if(IsObjectMenu())
{
for(int i = 0; i < pPopupMenu->GetMenuItemCount();i++)
{
MENUITEMINFO MenuItemInfo;
memset(&MenuItemInfo, 0, sizeof(MENUITEMINFO));
MenuItemInfo.cbSize = sizeof (MENUITEMINFO); // must fill up this field
MenuItemInfo.fMask = MIIM_SUBMENU;
if (!pPopupMenu->GetMenuItemInfo(i, &MenuItemInfo, TRUE))
continue;
CMenu* SubMenu = pPopupMenu->GetSubMenu(i);
if (SubMenu != NULL)
{
memset(&MenuItemInfo, 0, sizeof(MENUITEMINFO));
MenuItemInfo.cbSize = sizeof (MENUITEMINFO);
MenuItemInfo.fMask = MIIM_ID | MIIM_TYPE;
for(int j=0; j<SubMenu->GetMenuItemCount() ;j++ )
{
SubMenu->GetMenuItemInfo(j, &MenuItemInfo, TRUE);
if (MenuItemInfo.wID == ID_CREATE_OBJECTAS)
{
for (int i=0; i<m_custom_objects.GetSize(); i++)
pPopup->AppendMenu(MF_STRING | MF_ENABLED, WM_MENU_CUSTOM_OBJECTS_BEGIN + i, (LPCTSTR) m_custom_objects[i].GetName() );
found= true;
break;
}
}
if(found)
break;
}
}
}
}
__super::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);
}
注意 ID_FILE_SAVEAS_XXX
MENUITEM 标识符重复了!由于我不想在支持 "SaveAsFile" 的许可证不存在时删除 "Save Object" POPUP,因此绝对需要确定现在正在处理的菜单。
现在用户已经使用 MFC 自定义对话框创建了一个工具栏,然后他将 "Create Object" POPUP 拖到新的工具栏。当他单击工具栏的这个新按钮时,他会看到 "Create object" 和 "Create object as" 选项,但并不是因为 IsObjectMenu()
条件不满足而未附加自定义对象。当他来自主菜单时,行为完全不同;附加已完成!
当用户单击工具栏的按钮时,我如何编写代码以完成自定义对象的追加?
我并不为自己的代码感到骄傲,但我通过将"Object"的代码与"Create Object"菜单分开来解决了它。
bool CMainFrame::IsCreateObjectMenu(CMenu* pPopupMenu) const
{
if(!pPopupMenu);
return false;
return (pPopupMenu->GetMenuItemCount() > 0) && (pPopupMenu->GetMenuItemID(0) == ID_CREATE_OBJECT);
}
void CMainFrame::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu)
{
if(!license.supports("SaveAsFile"))
{
if(IsFileMenu())
{
//code to find ID_FILE_SAVEAS_XXX parent menu ("Save As"), then recursively delete all its descendants and itself
}
if(IsObjectMenu())
{
// Do things
}
if(IsCreateObjectMenu())
{
for (int i=0; i<m_custom_objects.GetSize(); i++)
pPopupMenu->AppendMenu(MF_STRING | MF_ENABLED, WM_MENU_CUSTOM_OBJECTS_BEGIN + i, (LPCTSTR) m_custom_objects[i].GetName());
}
}
__super::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);
}