views:

56

answers:

1

My main frame has a CMFCMenuBar member, which contains the menu of the current document type. I would like to add/remove a sub-menu dynamically. For example, if the user chooses to display a map pane, I want to add a map submenu next to the "File" menu.

Vice versa, if the map pane gets closed, I also want to remove the map menu items.

One thing that works but which I don't like is to simply disable the menu items in the ON_UPDATE_COMMAND_UI handlers.
The Frame has a method called GetMenuBar() but that one returns me a const CMFCMenuBar * so I can't modify it from the outside. I added a getter so I get a non-const reference to the menu bar but that didn't work either:

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

The above code is an adaption of void CMyMenuBar::AddSubMenu () in the DynamicMenu sample. I have the feeling though, that this sample is broken as I couldn't find out if or when that particular code is executed. In the sample, the code is only executed when the menu bar is being reset or when no state has been saved to the registry yet.

Is this just not possible or am I doing something wrong?

Would there be a nice alternative to adding/removing a sub-menu?

A: 

One way to do this is to handle the WM_INITMENUPOPUP message. Just before a menu is displayed, OnInitMenuPopup will get called with a pointer to the menu.

Note that this gets called each time the menu is about to pop up, and any changes you make are lost between invocations (you have to add your menu items each time OnInitMenuPopup is called).

The trick to using this is figuring out how to identify the menu that has been invoked. One way would be to compare the menu item ID of a known item. For example, if the first item on the menu is ID_FILE_OPEN, you could look for that. If found, you would assume that your “File” menu is the one being opened, and you could add your custom submenu.

Possibly you could also use the dwMenuData member of the MENUINFO struct, although I seem to recall having problems with this due to the way CMFCMenuBar builds the menu.

Nate
If I understand you correctly, this will allow me to remove all sub items of "Map" but not "Map" itself. The menu bar would then look like "File | Map | Edit | ..." with "Map" having no sub items; right? I think that would look more like a bug than a feature...
mxp
You could handle this message for the “File” menu, and use that to remove the “Map” sub-menu (if appropriate). But more likely you would *not* have a pre-defined “Map” sub-menu; you would just insert it into the “File” menu when needed. Each time you get `OnInitMenuPopup`, decide whether you need a “Map” sub-menu and add it if appropriate. Because the menu is always reset to it’s original version each time, you never need to worry about removing anything. You only need to *add* items that are appropriate for the context.
Nate