【问题标题】:Is it possible to manipulate the menu of my CMDIFrameWndEx's CMFCMenuBar?是否可以操作我的 CMDIFrameWndEx 的 CMFCMenuBar 的菜单?
【发布时间】:2011-04-23 22:42:28
【问题描述】:

我的主框架有一个 CMFCMenuBar 成员,其中包含当前文档类型的菜单。 我想动态添加/删除子菜单。 例如,如果用户选择显示地图窗格,我想在“文件”菜单旁边添加地图子菜单。

反之亦然,如果地图窗格关闭,我也想删除地图菜单项。

一个可行但我不喜欢的事情是简单地禁用ON_UPDATE_COMMAND_UI 处理程序中的菜单项。
Frame 有一个名为GetMenuBar() 的方法,但该方法返回给我const CMFCMenuBar *,因此我无法从外部对其进行修改。我添加了一个 getter,因此我获得了对菜单栏的非常量引用,但这也不起作用:

CMenu menu;
VERIFY(menu.LoadMenu(IDR_MAP));
CMFCMenuBar & menuBar = pFrm->GetNonConstMenuBar(); // Custom getter
menuBar.InsertButton(CMFCToolBarMenuButton(0, menu, -1));
menuBar.AdjustLayout();
menuBar.AdjustSizeImmediate();

以上代码是DynamicMenu示例中void CMyMenuBar::AddSubMenu ()的改编。 但我有一种感觉,这个示例被破坏了,因为我无法确定是否或何时执行该特定代码。在示例中,代码仅在菜单栏被重置时执行或尚未将状态保存到注册表时。

这是不可能的还是我做错了什么?

除了添加/删除子菜单有什么好的替代方法吗?

【问题讨论】:

    标签: c++ mfc dynamic menu mfc-feature-pack


    【解决方案1】:

    一种方法是处理WM_INITMENUPOPUP 消息。就在菜单显示之前,OnInitMenuPopup 将被调用,并带有指向菜单的指针。

    请注意,每次菜单即将弹出时都会调用它,并且您所做的任何更改都会在两次调用之间丢失(每次调用 OnInitMenuPopup 时都必须添加菜单项)。

    使用它的技巧是弄清楚如何识别已调用的菜单。一种方法是比较已知项目的菜单项 ID。例如,如果菜单上的第一项是 ID_FILE_OPEN,您可以查找它。如果找到,您会假设您的“文件”菜单是正在打开的菜单,您可以添加自定义子菜单。

    您可能还可以使用MENUINFO 结构的dwMenuData 成员,尽管我似乎记得由于CMFCMenuBar 构建菜单的方式而遇到了问题。

    【讨论】:

    • 如果我理解正确,这将允许我删除“地图”的所有子项,但不能删除“地图”本身。然后菜单栏看起来像“文件|地图|编辑| ...”,“地图”没有子项目;正确的?我认为这看起来更像是一个错误而不是一个功能......
    • 您可以为“文件”菜单处理此消息,并使用它来删除“地图”子菜单(如果合适)。但您更有可能没有有预定义的“地图”子菜单;您只需在需要时将其插入“文件”菜单即可。每次收到OnInitMenuPopup 时,请确定是否需要“地图”子菜单并在适当时添加。因为菜单每次都会重置为原始版本,所以您无需担心删除任何内容。您只需要添加适合上下文的项目。
    • 使用 OnInitMenuPopup()(WM_INITMENUPOPUP 的消息处理程序)是一种很酷且最好的菜单自定义方式。主要优点是任何自定义仅在当前调用中“活动”,如果您不再次处理,任何后续都不会进行自定义。
    • 当我开始将弹出菜单(具有后代的菜单)拖到工具栏时,这种方法给我带来了问题。该技巧的逻辑丢失了,因为当您拖动弹出窗口时,它们无法带来顶部菜单的第一项,并且该方法背后的整个理性就像纸牌屋一样倒塌!
    猜你喜欢
    • 1970-01-01
    • 2012-09-23
    • 2013-07-28
    • 2014-12-24
    • 2022-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    相关资源
    最近更新 更多