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 General Discussion » Dynamic menus Collapse All
Subject Author Date
chris fudge Mar 18, 2005 - 10:02 AM

Hi ,
How do I add menus dynamically at runtime. Ive found the artcle: http://www.prof-uis.com/FAQView.aspx?CID=96

And used it to add a buttons to the menu bar however I cannot get menus to be dynamically added to the buttons. I am not using menu resources, i intend to build up the menu on the fly.

Thanks

chris fudge Mar 18, 2005 - 10:28 AM

Here is my code for adding a menu to a previous added menu bar button :

HMENU hMenu = m_wndMenuBar.GetButtonMenu(m_wndMenuBar.CommandToIndex(pMenu->nParentID));
if(hMenu == 0)
{
CMenu _menu;
_menu.CreateMenu();
_menu.AppendMenu(MF_STRING,m_nTBButtonID,pMenu->szCaption);
m_wndMenuBar.SetButtonMenu
(
m_wndMenuBar.CommandToIndex(pMenu->nParentID),
_menu.GetSafeHmenu()
);
}

Im basically checking if there is already a menu assigned to the button, if there isnt then I create a new one and set it to the button. When i run the application however, it debug asserts on when I click the menu bar button (before the menu appears). The assertion occurs on line 1721 of ExtToolControlBar.cpp.

Technical Support Mar 19, 2005 - 10:08 AM

We guess you need to add new pop-up menus to the menu bar. If fact, the menu bar is a kind of toolbar. Each top level menu is a toolbar button with its submenu. The menu bar builds its toolbar buttons with submenus in the CExtMenuControlBar::_UpdateMenuBar() internal virtual method which you can override to insert your custom menus. To make the menu bar update itself (to call CExtMenuControlBar::_UpdateMenuBar()), you need to fire the update event from outside with m_wndMenuBar.UpdateMenuBar(). Please also note that pop-up menu buttons in the menu bar are also command items and must have their command descriptions in the command manager. The menu bar allocates these pop-up commands dynamically and marks their CExtCmdItem instances with the CExtCmdItem::STATE_MENUBAR_TMP flag. So, when the menu bar is re-built, it can remove all the previously allocated command items for popup buttons. You may not use these flag for your custom pop-up items, especially if the number of custom pop-up items in your application is constant.

chris fudge Mar 21, 2005 - 12:24 AM

Could you please provide and example of how i add popup menus to a menubar button. My code below si supposed to dynamically add a new menu item - if the new menu item has no parent id set then it adds a new menu bar button if the new item has a parent then it is supposed to add a menu item to the popup for the menu bar button item with the specified parent id. I currently have it adding the menu bar buttons ok, however now that i have added updatemenubar call, the menu bar buttons disappear.


BOOL CMainFrame::AddNewMenu(CMenuParam* pMenu)
{        
    if(m_nTBButtonID >= START_TBBUTTON_ID + MAX_TBBUTTON_COUNT) return FALSE;

    int nButtonsCount = m_wndMenuBar.GetButtonsCount();
    // Let’s append the separator to the end


    // A root item - add a new menu bar button
    if(pMenu->nParentID == 0)
    {
        // Let’s append the button specified with ID_YOUR_COMMAND
        m_wndMenuBar.InsertButton(nButtonsCount++,m_nTBButtonID);

        // Set it to zero to allow the command manager
        // to find the dynamic identifier atomatically
        UINT nCmdID = m_nTBButtonID;
        LPCTSTR strProfileName = g_CmdManager->ProfileNameFromWnd(m_wndMenuBar.GetSafeHwnd());
        ASSERT( strProfileName != NULL );
        CExtCmdItem * pCmdItem = g_CmdManager->CmdAllocPtr(strProfileName,nCmdID);
        ASSERT( pCmdItem != NULL );
        pCmdItem->m_sTipTool = pMenu->szCaption;
        pCmdItem->m_sTipStatus = pMenu->szCaption;
        pCmdItem->m_sMenuText = pMenu->szCaption;
        pCmdItem->m_sToolbarText = pMenu->szCaption;
        pCmdItem->m_nLParamUserData = pMenu->nPluginID;
        CFrameWnd * pFrame = m_wndMenuBar.GetParentFrame();
        ASSERT_VALID( pFrame );
        pFrame->RecalcLayout();
        *pMenu->pMenuID = m_nTBButtonID;
        m_nTBButtonID++;
    }
    else        // Need to add a popup menu to the parent menu bar button here
    {
        m_wndMenuBar.UpdateMenuBar();
    }
return TRUE;
}

Technical Support Mar 21, 2005 - 5:23 AM

We have coded a a sample for you. Please take a look at the CMyMenuControlBar::DoInitMyCustomButtons() method. It creates one custom pop-up menu item in the menu bar.

chris fudge Mar 21, 2005 - 5:32 AM

I get the following error when i try to build the sample:

test_dyn_menu_bar\ChildView.cpp(57) : error C2664: ’PaintDockerBkgnd’ : cannot convert parameter 1 from ’const bool’ to ’class CDC &’

The error is in the onpaint handler in ChildView:

void CChildView::OnPaint()
{
CRect rcClient;
    GetClientRect( &rcClient );
CPaintDC dcPaint( this );
CExtMemoryDC dc( &dcPaint, &rcClient );
    if(        (! g_PaintManager->GetCb2DbTransparentMode(this) )
        ||    (! g_PaintManager->PaintDockerBkgnd( true, dc, this ) )
        )
        dc.FillSolidRect(
            &rcClient,
            g_PaintManager->GetColor(
                CExtPaintManager::CLR_3DFACE_OUT
                )
            );
}

chris fudge Mar 21, 2005 - 5:48 AM

I got it compiling by commenting out the true param:

(! g_PaintManager->PaintDockerBkgnd(/* true,*/ dc, this )

Is this because i am maybe running an old version of the profuis lib?

Thanks

chris fudge Mar 21, 2005 - 6:03 AM

Your sample uses a resource for the dynamic menu creation:

VERIFY(_menu.LoadMenu(IDR_MY_CUSTOM_POPUP));

I want to create the menu on the fly using AppenMenu/CreatePopupMenu etc.

Please could you provide an example that doesnt use a menu resource. My app wipes out when i try using append menu :

CMenu _menu;
_menu.CreatePopupMenu();
_menu.AppendMenu(MF_STRING,ID_MYTEST,_T("TEST"));

Technical Support Mar 21, 2005 - 6:02 AM

If you have an earlier version of Prof-UIS (earlier than Prof-UIS 2.30), please replace

(! g_PaintManager->PaintDockerBkgnd( true, dc, this ) )
with
(! g_PaintManager->PaintDockerBkgnd(  dc, this ) )

chris fudge Mar 21, 2005 - 6:17 AM

Your sample uses a resource for the dynamic menu creation:

VERIFY(_menu.LoadMenu(IDR_MY_CUSTOM_POPUP));

I want to create the menu on the fly using AppenMenu/CreatePopupMenu etc.

Please could you provide an example that doesnt use a menu resource. My app wipes out when i try using append menu :

CMenu _menu;
_menu.CreatePopupMenu();
_menu.AppendMenu(MF_STRING,ID_MYTEST,_T("TEST"));

Technical Support Mar 22, 2005 - 5:56 AM

Prof-UIS menus can operate with command items of two types:

  1. Command items based on the command manager. Any menu item in this case stores only its command identifier. All other information (text, tooltip text, icon and etc.) is stored in the CExtCmdItem object inside the command manager. These menu items are inserted into a menu by calling CExtPopupMenuWnd::ItemInsert(), CExtPopupMenuWnd::LoadMenu() or CExtPopupMenuWnd::UpdateFromMenu(). It is the CExtPopupMenuWnd::UpdateFromMenu() method that is used by any button in the menu bar for creating its pop-up menu window. All commands in this menu are already registered in the command manager by invoking g_CmdManager->UpdateFromMenu() in the CMainFrame::OnCreate() method. So, you cannot use both CMenu and HMENU for building dynamic menus.
  2. Command items which have no reference to the command manager and which are even never updated with the MFC command updating mechanism. These command items appear in Prof-UIS menus by calling CExtPopupMenuWnd::ItemInsertCommand(). You should use these commands for building your custom pop-up menus. To create a pop-up menu on-the-fly, just handle the CExtPopupMenuWnd::g_nMsgPrepareMenu registered windows message in your main frame or dialog window:
    ON_REGISTERED_MESSAGE(
            CExtPopupMenuWnd::g_nMsgPrepareMenu,
            OnExtMenuPrepare
            )
        LRESULT CMainFrame::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 );
     
            // TO DO: modify pPopup menu here
            return TRUE;
        }
    What is the way of finding out whether you should modify the pPopup menu? The most convenient way is to use some pre-defined command identifiers, find them with pPopup->ItemFindPosForCmdID(), remove menu item(s) with pPopup->ItemRemove() and insert any number of new dynamic items by using pPopup->ItemInsert() or pPopup->ItemInsertCommand(). This technique is used for building OLE verb menus in the DRAWCLI sample. You can also use our sample project we sent you: Only leave one pre-defined item in the custom pop-up menu and handle the CExtPopupMenuWnd::g_nMsgPrepareMenu registered windows message like we described above.

    Of course, we can help you code this task, but we need a more detailed description.

    Please note that the differences in design of Prof-UIS menus and Win32 menus allow our menus to operate with absolutely custom pop-up menus (e.g. a color picker menu). So, having overcome some inconvenience while porting your code to Prof-UIS menus, you get more than a menu.