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 » Toolbar popup menu without customization Collapse All
Subject Author Date
Holger Hellenschmidt Jun 3, 2005 - 7:40 AM

Hi,


I want to realize a toolbar button with a simple popup menu. I have implemented it as described in your online help, but as soon as I enable customization (CExtCustomizeSite::EnableCustomization) the menu ist alwasy empty. Where do I have to register the popup menu?

Technical Support Jun 5, 2005 - 8:43 AM

After the customization subsystem is initialized, all toolbars and menus get based on command tree nodes (the CExtCustomizeCmdTreeNode class). There are two approaches to this task. The first is based on direct access to the command tree node of the toolbar button and creating its child nodes. As a result, such a button gets a menu because its command tree node contains child nodes. You can get a pointer to the CExtBarButton object (that implements the toolbar button) by calling the CExtToolControlBar::GetButton() and CExtToolControlBar::CommandToIndex() methods. Then you can get a pointer to the CExtCustomizeCmdTreeNode object of the toolbar’s button by invoking the CExtBarButton::GetCmdNode() method. After that you can construct child nodes. Please note that each toolbar button is linked to two command tree nodes. The current command tree node describes the currently displayed button whose properties can be changed by the user in the customize mode. The initial command tree node describes the toolbar button in its initial state (when the application starts for the first time or when the user presses Reset on the Customize dialog). The initial node is required for reset the toolbar button in the customize mode. We must admit that this solution is a bit complicated because the user can always drag-and-drop your toolbar button to any other toolbar or menu. So, you would have to traverse all the sub trees of all the toolbars and menus, locate your toolbar button’s drag-and-dropped copies and initialize them.

The alternative approach is very simple and based on marker commands. You create a pop-up menu resource with one command item that is called marker. Then you assign this menu to the toolbar button before the customization subsystem is initialized. Now your toolbar button has a menu with only one marker command item and you need to handle the CExtPopupMenuWnd::g_nMsgPrepareMenu or CExtPopupMenuWnd::g_nMsgPrepareOneMenuLevel registered windows messages which allow you to modify any pop-up menu before it appears on the screen. Your handler method just finds the marker command item in the pop-up menu being constructed, removes the marker and inserts some other menu items which, in your case, depend on the list selection. The CExtPopupMenuWnd::g_nMsgPrepareMenu registered windows message is sent once for each menu tree which allows you to analyze the entire menu tree that is constructed. The CExtPopupMenuWnd::g_nMsgPrepareOneMenuLevel registered windows message is introduced in Prof-UIS 2.33. It is similar to the previous message but is invoked for each single pop-up menu sublevel before it appears on the screen. This makes it handy for constructing menus which have many submenus. Your list selection dependent menu will be always correct even if the user drag-and-drop the marker item to any other menu in the customize mode. Here is the declaration, message map entry and implementation for the CExtPopupMenuWnd::g_nMsgPrepareOneMenuLevel registered windows message handler:

afx_msg LRESULT OnExtMenuPrepare(
    WPARAM wParam, LPARAM lParam );
ON_REGISTERED_MESSAGE(
    CExtPopupMenuWnd::g_nMsgPrepareOneMenuLevel,
    OnExtMenuPrepare
    )
LRESULT CDrawView::OnExtMenuPrepare(
    WPARAM wParam, LPARAM lParam )
{
    lParam;
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_YOUR_MARKER_COMMAND
            );
    for( ; nReplacePos >= 0;
            nReplacePos =
                pPopup->ItemFindPosForCmdID(
                    ID_YOUR_MARKER_COMMAND )
        )
    {
        VERIFY( pPopup->ItemRemove( nReplacePos ) );
        // insert new menu items into
        // the nReplacePos position
    }
    return TRUE;
}
Please note that this method absolutely correctly assumes that the marker command item can be presented more than once in any pop-up menu because your application is customizable and everything can be moved or copied to any other location.

Holger Hellenschmidt Jun 6, 2005 - 2:30 AM

Hi,


is there really no possibility to display a simple popup menu on a toolbar button. Is it possible to catch the event when pressing the toolbar button and display an own popup menu?

Technical Support Jun 3, 2005 - 9:37 AM

Please note that both toolbars and menus in customizable applications are based on the command trees (the CExtCustomizeCmdTreeNode class) controlled by the customize site (the CExtCustomizeSite class). So, any menu bar button and toolbar button with drop-down menu contains its own command tree node instead of a HMENU handle. To find a solution how to create the toolbar button with drop-down menu, take a look at the CMainFrame::OnCreate() method of the DRAWCLI sample that can be compiled both as a customizable application and as non-customizable too. In both cases, this application creates the "line width" toolbar button with the drop-down menu:

INT nBtnIdx = m_wndToolBarStandard.CommandToIndex(ID_DOC_LINE_WIDTH);
    ASSERT( nBtnIdx >= 0 );
CMenu _line_menu;
    VERIFY( _line_menu.LoadMenu(IDR_MENU_LW) );
    VERIFY( m_wndToolBarStandard.SetButtonMenu( nBtnIdx, _line_menu.Detach() ) );
CExtBarButton * pTBB = m_wndToolBarStandard.GetButton(nBtnIdx);
    ASSERT_VALID( pTBB );
    pTBB->SetNoRotateVerticalLayout();
    pTBB->SetSeparatedDropDown();
    pTBB->SetAutoChangeID();
    pTBB->SetCmdID(ID_LINE_WIDTH_1,true); // set default effective command
The call of the CExtCustomizeSite::EnableCustomization() method close to the end of the CMainFrame::OnCreate() method simply converts all the toolbars and menus and makes them using command tree nodes of the customization system. The command manager is not updated from the IDR_MENU_LW menu resource because all its commands are available in other menu resources which are used for building the command manager’s command set at the beginning of the CMainFrame::OnCreate() method.

We may guess, the same method of your main frame window contains an invalid sequence of API invocations. Please compare it with that in the DRAWCLI sample or send it to us.

Holger Hellenschmidt Jun 5, 2005 - 3:06 AM

Thank’s for your response, but I cannot create the menu before CExtCustomizeSite::EnableCustomization() is called because it’s a dynamic menu which depends on the current selection of a list control. The menu is also not a submenu of the main menu.


How can I add a toolbar button menu after EnableCustomization is called?

Technical Support Jun 6, 2005 - 6:20 AM

You can create a CExtBarButton-derived class and override the CExtBarButton::OnTrackPopup() virtual method in which you need to create and track your own pop-up menu. You also have to override the CExtBarButton::PutToPopupMenu() virtual method which is invoked when your button creates its specific pop-up menu and inserts it into the pop-up menu of the chevron button. You can use the CExtBarColorButton class as a sample for this task. The CExtBarColorButton class implements a color picker button which creates and tracks a color picker menu. Please do not forget to override the CExtBarButton::IsAbleToTrackMenu() virtual method that should return true because it is essential to make your button having a look of toolbar’s drop-down button. You can insert your button to the toolbar with the CExtToolControlBar::InsertSpecButton() method. But we recommend you override the CExtCustomizeSite::OnCreateToolbarButton() virtual method in the main frame window of your customizable application in which you need to create your CExtBarButton-derived instance for the command tree node with an appropriate command identifier.