Professional UI Solutions
Site Map   /  Register
 
 

Forum

Please Log In to post a new message or reply to an existing one. If you are not registered, please register.

NOTE: Some forums may be read-only if you are not currently subscribed to our technical support services.

Forums » Prof-UIS Tech Support » Append Menu problem Collapse All
Subject Author Date
Offer Har Jun 9, 2006 - 12:51 PM

Hi,
I am using AppendMenu for adding items into a sub-menu like this:
pSubMenu->AppendMenu(MF_STRING, ID_XXX, str);

In a standard MFC application this works fine, but when the menu is a CExtMenuControlBar menu, the text is not displayed, only the menu item.
What am i missing?

Technical Support Jun 10, 2006 - 11:49 AM

The CExtMenuControlBar class is derived from CExtToolControlBar, which implements a toolbar in Prof-UIS. Any Prof-UIS toolbar is a window which contains CExtBarButton objects. That means the top-level menu in the menu bar is not based on HMENU handles. The menu bar creates its buttons in the CExtMenuControlBar::_UpdateMenuBar() virtual method which is invoked when the menu bar is created in an SDI/MDI application, when the CExtMenuControlBar::LoadMenuBar() method is invoked and when an MDI child frame is switched, created or destroyed in an MDI application. Please provide us with more details and some code snippets so we can help you.

Offer Har Jun 10, 2006 - 5:50 PM

Hi,

My task is to have a dynamic sub-menu. I know that the sub-menu is under "Display"\"SomeCommand", so i used to use GetMenuString to find the "Display" command, then again to find the "SomeCommand", and then using AppendMenu, i added menu commands to the sub-menu.

What are the function that i should use to implement the same task in the CExtMenuControlBar based menu?

Thanks.

Technical Support Jun 13, 2006 - 4:50 AM

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.

Offer Har Jun 13, 2006 - 5:30 AM

Hi,

All works great, but a small issue - The ON_UPDATE_COMMAND_UI for the items in the new sub-menu are not called. And strangely enough, when the menu item is pressed, this is when the command ON_UPDATE_COMMAND_UI is called..
Any ideas?


Thanks.

Technical Support Jun 13, 2006 - 10:43 AM

If the pop-up menu has been modified, the pData->m_bMenuChanged property should be set to true. It is important, so please check this.

Offer Har Jun 13, 2006 - 11:07 AM

The last line in the fucntion OnExtMenuPrepareOneLevel is pData->m_bMenuChanged = true; just before return 1L;
Still, the onupdate are not called.

Technical Support Jun 14, 2006 - 9:30 AM

We cannot yet confirm that it is a bug. Please download an updated version of the ProfUIS_Controls sample.

You can select the Popup Menus page and invoke the context menu over it. You will see the following two lines in the output window of the Visual Studio:

>>>>> CPagePopupMenus::OnUpdateMenuRarelyItem1()
>>>>> CPagePopupMenus::OnUpdateMenuRarelyItem1()


You will see only one of these lines if you comment the following message map entry for the CPagePopupMenus class:

    ON_REGISTERED_MESSAGE(
        CExtPopupMenuWnd::g_nMsgPrepareMenu,
        OnExtMenuPrepare
        )
You will see two lines in the first case because the CPagePopupMenus::OnUpdateMenuRarelyItem1() method is invoked by the command updating mechanism twice. First time, after initializing the menu. Second time, after handling the CExtPopupMenuWnd::g_nMsgPrepareMenu registered windows message in the CPagePopupMenus::OnExtMenuPrepare() method which has the following code at the beginning:
CExtPopupMenuWnd::MsgPrepareMenuData_t * pData =
        reinterpret_cast
        < CExtPopupMenuWnd::MsgPrepareMenuData_t * >
        ( wParam );
    ASSERT( pData != NULL );
CExtPopupMenuWnd * pPopup = pData->m_pPopup;
    ASSERT( pPopup != NULL );
    pData->m_bMenuChanged = true; 

Offer Har Jun 14, 2006 - 3:07 PM

Hi,

I am using ON_REGISTERED_MESSAGE(CExtPopupBaseWnd::nMsgPrepareOneMenuLevel...) and not CExtPopupMenuWnd::g_nMsgPrepareMenu, maybe this is the source of the problem.
Please check with nMsgPrepareOneMenuLevel, i think this is the place of the problem.

Thanks.

Technical Support Jun 16, 2006 - 12:51 PM

We checked CExtPopupMenuWnd::g_nMsgPrepareOneMenuLevel message. It is sent from the beginning of the CExtPopupMenuWnd::_TrackPopupMenu() method and invokes the command updating if needed:

MsgPrepareMenuData_t _mpmOneTreeLevel( this );
    _mpmOneTreeLevel.SendMessage( m_hWndCmdReceiver, true );
    if( _mpmOneTreeLevel.m_bMenuCanceled )
        return FALSE;
    if( _mpmOneTreeLevel.m_bMenuChanged )
    {
        _SyncItems();
        _UpdateCmdUI();
    }
Would you check command identifiers in your popup menus and message map entries with method names additionally?