MFC SDI 使用 SetMenu 更改菜单但如何更改加速器?

MFC SDI changed menu using SetMenu but how to change accelerators?

我有一个 SDI 应用程序。我想在 运行 时间内根据特定条件更改菜单。

我使用这个代码块来更改菜单并且它完成了它的工作。

menu = GetMenu();
SetMenu(NULL);
menu->DestroyMenu();
menu->LoadMenu(IDR_MAINFRAM_2));
SetMenu(menu);

我唯一的问题是新菜单的快捷键不起作用。 我已经创建了 ID 为 IDR_MAINFRAM_2 的加速器资源,但它并没有解决我的问题。 我应该怎么做才能解决这个问题?

可能您的方法根本不是最好的方法。如果您想在 运行 时间更改菜单,我的建议是您在互联网上搜索 ON_WM_INITMENUON_WM_INITMENUPOPUP

第一个适用于框架的硬编码菜单,第二个是当您使用 MFC 功能包时,并且您在框架 class 中声明了某些内容 CMFCMenuBar。看你的代码,一眼看去,好像是第一种情况。

这很简单。假设您从 CFrameWndEx 派生的 class 进行操作,只需调用:

LoadAccelTable(MAKEINTRESOURCE(IDR_MAINFRAM_2));

MFC 将为您处理该加速器table

很抱歉回复晚了。

我实际上使用了一个解决方法来解决这个问题,那就是确保不同菜单的加速器不会发生冲突,并让默认菜单的加速器 table 处理所有加速器。但是当相应的菜单项未显示时,我必须保存菜单状态并避免使用其他菜单的加速键。

嗯,这不是一个好的解决方法。但我成功了。

今天我试图验证我收到的答案以接受正确的答案。总结是:

我不需要 IInspectable 声明的对 TranslateAccelerator 的调用。 按照 Vlad 建议的方式加载加速器可以解决问题,但是当您调用 LoadAccelTable 时断言失败,因为它可以从该函数的 documentation 中读取,该函数声明该函数应该只调用一次。

所以我通过调用DestroyAcceleratorTable函数并将CFrameWnd::m_hAccelTable设置为NULL来克服它。在调用 LoadAccelTable 之前。

对于那些想像我一样更改 SDI 或 MDI 应用程序菜单的人,还有一个子注释。这也导致了一个,不知道为什么,断言失败,这是通过使用 article.

中建议的方法克服的

总而言之,如果提供的 link 变得不可用,它会说:

  1. Create a new menu resource (IDR_MYMENU1) in the resource editor.
  1. Add an HMENU data member to CMyDocument and override GetDefaultMenu() to return this data member:
// .h file
//    HMENU m_hMyMenu;
//    virtual HMENU GetDefaultMenu(); // get menu depending on state
HMENU CMyDocument::GetDefaultMenu()
{
   return m_hMyMenu;    // just use original default
}

Remember to initialize this member variable to NULL either in the constructor or CDocument::OnNewDocument().

  1. Change and redraw the menu at the desired times. For example, when switching between splitter panes, this is normally done in CView::OnActivateView(). The following code shows how to implement it in that function.

    // example within CView member function ((CMyDocument*)GetDocument())->m_hMyMenu = ::LoadMenu( AfxGetResourceHandle(), MAKEINTRESOURCE(IDR_MYMENU1)); ((CFrameWnd*)AfxGetMainWnd())->OnUpdateFrameMenu(NULL); AfxGetMainWnd()->DrawMenuBar();

Be sure to destroy the menu upon exiting the application, and avoid having too many menus loaded at once.

Menus can also be switched simply by changing the value of CMDIChildWnd::m_hMenuShared (MDI) or CFrameWnd::m_hMenuDefault (SDI). However, using GetDefaultMenu() allows a safer method of changing the menus.

还要确保不要破坏默认菜单:

if (m_hMenuDefault != GetMenu()->m_hMenu)
    GetMenu()->DestroyMenu();