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_INITMENU
和 ON_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 变得不可用,它会说:
- Create a new menu resource (IDR_MYMENU1) in the resource editor.
- 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().
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();
我有一个 SDI 应用程序。我想在 运行 时间内根据特定条件更改菜单。
我使用这个代码块来更改菜单并且它完成了它的工作。
menu = GetMenu();
SetMenu(NULL);
menu->DestroyMenu();
menu->LoadMenu(IDR_MAINFRAM_2));
SetMenu(menu);
我唯一的问题是新菜单的快捷键不起作用。 我已经创建了 ID 为 IDR_MAINFRAM_2 的加速器资源,但它并没有解决我的问题。 我应该怎么做才能解决这个问题?
可能您的方法根本不是最好的方法。如果您想在 运行 时间更改菜单,我的建议是您在互联网上搜索 ON_WM_INITMENU
和 ON_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 变得不可用,它会说:
- Create a new menu resource (IDR_MYMENU1) in the resource editor.
- 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().
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();