Prof-UIS menus are not based on HMENU
handles. They are based on CExtPopupMenuWnd
windows. So you cannot use the WM_INITMENUPOPUP
and WM_INITMENU
messages here.
There are two registered windows messages in Prof-UIS CExtPopupBaseWnd::g_nMsgPrepareMenu
and CExtPopupBaseWnd::g_nMsgPrepareOneMenuLevel
(starting from Prof-UIS 2.33). The CExtPopupBaseWnd::g_nMsgPrepareMenu
message is sent only once for each menu tree and allows you to analyze the entire menu tree before it appears on the screen. The CExtPopupBaseWnd::g_nMsgPrepareOneMenuLevel
message is similar to the previous message but it is sent for each single pop-up menu sublevel before it appears on the screen. This makes it handy to construct menus with many submenus.
Let’s assume that we need to insert some new menu items at a certain position in a popup menu. First, we need to open the menu resource and insert some ID_MY_MENU_MARKER
command in the popup menu. The menu item text and tip text properties of this item are not important at all. This command item will be replaced with a set of dynamic menu items on-the-fly immediately before the menu appears on the screen. Now, we need to handle the CExtPopupBaseWnd::g_nMsgPrepareOneMenuLevel
registered windows message in the application. The message handler function, which should be added to the main frame or dialog window, should make a search for the ID_MY_MENU_MARKER
menu item in each displayed sub menu. If this menu item is found, the handler method removes this menu item and inserts new items instead. Here is the method declaration, message map’s entry and implementation.
Method declaration
afx_msg LRESULT OnExtMenuPrepareOneLevel(WPARAM wParam, LPARAM lParam);
Message map entry
ON_REGISTERED_MESSAGE(
CExtPopupBaseWnd::g_nMsgPrepareOneMenuLevel,
OnExtMenuPrepareOneLevel
)
Method implementation
LRESULT CMainFrame::OnExtMenuPrepareOneLevel( WPARAM wParam, LPARAM lParam )
{
lParam; // unused parameter
CExtPopupMenuWnd::MsgPrepareMenuData_t * pData =
reinterpret_cast < CExtPopupMenuWnd::MsgPrepareMenuData_t * > ( wParam );
ASSERT( pData != NULL );
CExtPopupMenuWnd * pPopup = pData->m_pPopup;
ASSERT( pPopup != NULL );
INT nReplacePos =
pPopup->ItemFindPosForCmdID( ID_MY_MENU_MARKER );
if( nReplacePos < 0 )
return 0;
VERIFY( pPopup->ItemRemove(nReplacePos) );
// insert one command
pPopup->ItemInsertCommand(
ID_APP_ABOUT,
nReplacePos,
"About (1)"
);
// insert one more command
pPopup->ItemInsertCommand(
ID_APP_ABOUT,
nReplacePos + 1,
"About (2)"
);
// and insert one more command
pPopup->ItemInsertCommand(
ID_APP_ABOUT,
nReplacePos + 2,
"About (3)"
);
return 1L;
}
As you can see, to find a menu item by its command identifier, you can use the
CExtPopupMenuWnd::ItemFindPosForCmdID()
method. This method retrieves the menu item position from the command id. If the item is not found methods returns -1.
If the pop-up menu has been modified, the
pData->m_bMenuChanged
property should be set to
true
. To cancel pop-menu tracking, set
pData->m_bMenuCanceled
to
true
.
You may also rebuild the top level of the menu bar. The menu bar (
CExtMenuControlBar
) is based on the toolbar (
CExtToolControlBar
). The
CExtMenuControlBar::UpdateMenuBar()
method invokes an algorithm that rebuilds menu bar’s buttons. You can implement your own algorithm of filling the menu bar with buttons (
CExtBarButton
). Create your own
CExtMenuControlBar
-derived class and override the
CExtMenuControlBar::_UpdateMenuBar()
internal virtual method. Your method can be either based on the original method (you only embed buttons you want) or completely rebuild an array of buttons in your own manner. All the commands inside the menus attached to the menu bar buttons should be registered in the command manager. The top level buttons in the menu bar also have their unique command identifiers and should be allocated exactly like it is done in the
CExtMenuControlBar::_UpdateMenuBar()
method.