关于视觉c:从工具栏按钮(它是应用程序主菜单栏中的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,该菜单的定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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),要知道我在哪个菜单上进行初始化,我按照https://stackoverflow.com/a/3910405/383779上的方法进行操作,并且已实现的功能,例如

1
2
3
4
5
6
7
8
9
10
11
12
13
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);
}

菜单初始化类似于:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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"的许可证不存在时,我不想删除"保存对象" POPUP,因此绝对需要确定正在处理的菜单。

现在,用户已经使用" MFC自定义"对话框创建了一个工具栏,然后将"创建对象" POPUP拖动到新的工具栏上。当他单击工具栏的此新按钮时,他看到"创建对象"和"创建对象为"选项,但是由于未满足IsObjectMenu()条件,未附加自定义对象。当他来自主菜单时,行为是完全不同的。追加已完成!

当用户单击工具栏上的按钮时,如何以完成自定义对象添加的方式编写代码?


我不为自己的代码感到骄傲,但是我通过将" Object "的代码与" Create Object "菜单中的代码分开来解决了这个问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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);
}