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 » CExtMenuControlBar Collapse All
Subject Author Date
YS Jang Jul 25, 2006 - 2:14 AM

Hi.

I use the CExtMenuControlbar and want to change the text(menu title) of menuitem on runtime.

I have two problems.

1. My Application’s menu text is not changed.
(The menu without Command ID is changed. but others are not changed)

CMainFrame::MenuTextChange()
{
CMenu *pMenu, *pSubMenu;

pMenu = m_wndMenuBar.GetMenu();//CExtMenuControlBar m_wndMenuBar
pMenu->ModifyMenu(0, MF_STRING|MF_BYPOSITION, NULL, "Test"); //Good work ...Without Command ID

pSubMenu = pMenu.GetSubMenu(0);
pSubMenu->ModifyMenu(0, MF_STRING|MF_BYPOSITION, ID_FILE_EXIT, "Exit"); // The Menu text is not Changed
........
}


2. Some menuitem is changed but the menuitem’s status is diable


How to can I resove?
thanks....



pMenu = m_wndMenuBar.GetMenu

Technical Support Jul 25, 2006 - 7:35 AM

You should not use the CExtMenuControlBar::GetMenu() method because it’s for internal purposes only. The menu bar is a kind of toolbar. Its buttons are CExtBarButton objects. You can rebuild its buttons using the CExtMenuControlBar::UpdateMenuBar() method. The latter invokes the CExtMenuControlBar::_UpdateMenuBar() virtual method, which recreates all the CExtBarButton objects representing menu bar’s buttons. So you can create a CExtMenuControlBar-derived class and override its _UpdateMenuBar() virtual method, which should be similar to the original one but you need to use your own algorithm of assigning names to buttons.
The article Constructing Menus Dynamically at Run Time may be helpful with this.

YS Jang Jul 25, 2006 - 5:38 PM

thanks.

But I don’t need to create a new menuitem. I just want to change the text of menuitem that is created already.
I’m searching your article and CExtPopupMenuWnd’s functions but I didn’t found how to change the text of menu.



Suhai Gyorgy Jul 26, 2006 - 2:03 AM

Hi!

If you know the ID of the command, this is what I’m using:

CExtCmdItem * pCmdItem = g_CmdManager->CmdGetPtr( g_CmdManager->ProfileNameFromWnd(AfxGetMainWnd()->GetSafeHwnd()), _ID_FILE_EXIT );
ASSERT (pCmdItem != NULL );

pCmdItem->m_sMenuText = "Exit";
//pCmdItem->m_sAccelText = "Some accelerator";
//pCmdItem->m_sTipStatus = "Tips appearing in StatusBar";
//pCmdItem->m_sTipTool = "Tips appearing in popup Tooltip";

Regards:
Chris

Technical Support Jul 26, 2006 - 5:30 AM

Any menu item in the top level menu line is a CExtBarButton object in the CExtMenuControlBar window. If you want modify some item (or create or remove), you should implement your own CExtMenuControlBar::_UpdateMenuBar() virtual method as we suggested earlier. If you want to modify a menu item somewhere in a pop-up that is invoked from the menu line, then you should handle the CExtPopupMenuWnd::g_nMsgPrepareOneMenuLevel registered windows message, which is sent before any sub menu appears on the screen and allows you to build or change any popup menu. This message should be handled in your main frame window:

ON_REGISTERED_MESSAGE(
    CExtPopupMenuWnd::g_nMsgPrepareOneMenuLevel,
    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 );
// MODIFY pPopup HERE USING CExtPopupMenuWnd METHODS
 
    pData->m_bMenuChanged = true; // invoke this line if menu was changed
    return 1;
}

YS Jang Jul 27, 2006 - 5:58 AM

Thanks..

I have tried to change the menu text the way above article.
but I didn’t get a result

then.

I found the solution to resolve my problems due to Suhai Gyorgy....
thanks Gyorgy

OK. Is My Coding correct?




void CMainFrame::SetLanguageFile(DWORD dwLanguage)
{
CString strLanguagePath = _T("");


switch(dwLanguage)

{

case LANGUAGE_ENGLISH:

m_fileOptionLanguage.m_strFileName= "Language\\English.ini";

break;

default:

m_fileOptionLanguage.m_strFileName= "Language\\English.ini";

break;

}


CString strName;

CMenu *pMenu, *pSubMenu;
pMenu = m_wndMenuBar.GetMenu(); //CExtMenuControlBar m_wndMenuBar

//File

strName = m_fileOptionLanguage.IniFileReadStringEx("MENU", "ID_MENU_FILE","");

pMenu->ModifyMenu(0, MF_STRING|MF_BYPOSITION, NULL, (LPSTR)(LPCTSTR)strName);


strName = m_fileOptionLanguage.IniFileReadStringEx("MENU","ID_MENU_FILE_EXIT","");
CExtCmdItem * pCmdItem = g_CmdManager->CmdGetPtr( g_CmdManager->ProfileNameFromWnd(AfxGetMainWnd()->GetSafeHwnd(), ID_FILE_EXIT );

ASSERT (pCmdItem != NULL );
pCmdItem->m_sMenuText = strName;

m_wndMenuBar.UpdateMenuBar();
}

Technical Support Jul 27, 2006 - 9:30 AM

No, your code is not correct because you should not use the CExtMenuControlBar::GetMenu() method. The returned CMenu even can be a temporary menu. The CExtMenuControlBar::GetMenu() method is for internal use only. Please follow the advice on how to implement the CExtMenuControlBar::_UpdateMenuBar() virtual method.

Suhai Gyorgy Jul 27, 2006 - 6:52 AM

You should consider using a CExtMenuControlBar-derived class and override CExtMenuControlBar::_UpdateMenuBar() virtual method as Support suggested (I’m myself using this same approach).

Also you should consider to modify top menu items the same way as command items, using CExtCmdItem, especially if you are using customize.

This can be done by this code, if you know that ID_MENU_FILE is on the 0. position:

    UINT nCmdId = m_wndMenuBar.GetButton(0)->GetCmdID();
    CExtCmdItem *pCmdItem = g_CmdManager->CmdGetPtr(
                    g_CmdManager->ProfileNameFromWnd(AfxGetMainWnd()->GetSafeHwnd()),
                    nCmdId
                    );
    ASSERT( pCmdItem != NULL );
    pCmdItem->m_sToolbarText = m_fileOptionLanguage.IniFileReadStringEx("MENU", "ID_MENU_FILE","");

Here you have to use m_sToolbarText, because top menu items are really Toolbar buttons showing text instead of icon.

Regards:
Chris.

YS Jang Jul 28, 2006 - 1:16 AM

thanks...

Good working!

I added a CMainMenuClass that is a CExtMenuControlBar-derived class and CExtMenuControlBar::_UpdateMenuBar() virtual method as your advice.

CMainMenuBar::_UpdateMenuBar()
{
CMenu* pMenu = GetMenu();
.....
}

then, The UpdateMenuBar() is called when menu is created.

But, I need to change the text of menu items when I Click the menu item (ex. View->Language->English)

I have changed the my code.

I added a CMainMenuClass that is a CExtMenuControlBar-derived class and CExtToolControlBar::GetButton() and GetButtonMenu() virtual method.

CExtButtonBar* CMainMenuBar :: GetButton(int nIndex)
{
return CExtToolControlBar::GetButton(nIndex);
}

HMENU CMainMenuBar::GetButtonMenu(int nIndex)
{
return CExtToolControlBar::GetButtonMenu(nIndex);
}

Have My code is a problem?


Suhai Gyorgy Jul 28, 2006 - 2:03 AM

In one of your previous messages you had a method called SetLanguageFile. I’m guessing that method is called from the command handler of your View->Language->English command. If you call m_wndMenuBar.UpdateMenuBar() in that SetLanguageFile method, then your overriden CMainMenuBar::_UpdateMenuBar() will get called. In that CMainMenuBar::_UpdateMenuBar() you should somehow get access to your m_fileOptionLanguage variable and use it to do all the modifying of strings.

I don’t think you need to override GetButton and GetButtonMenu methods. CExtMenuControlBar is derived from CExtToolControlBar anyway.

And as support said, do not use GetMenu() at all anywhere in your code.

This is how I can imagine your code:

void CMainFrame::SetLanguageFile(DWORD dwLanguage)
{
CString strLanguagePath = _T("");
switch(dwLanguage)
{
case LANGUAGE_ENGLISH:
m_fileOptionLanguage.m_strFileName= "Language\\English.ini";
break;
default:
m_fileOptionLanguage.m_strFileName= "Language\\English.ini";
break;
}

// ini file processing, like opening and all

m_wndMenuBar.UpdateMenuBar(); //now CMainMenuBar::_UpdateMenuBar(BOOL bDoRecalcLayout) gets called

//change Exit command string
strName = m_fileOptionLanguage.IniFileReadStringEx("MENU","ID_MENU_FILE_EXIT","");
CExtCmdItem * pCmdItem = g_CmdManager->CmdGetPtr( g_CmdManager->ProfileNameFromWnd(AfxGetMainWnd()->GetSafeHwnd(), ID_FILE_EXIT );
ASSERT (pCmdItem != NULL);
pCmdItem->m_sMenuText = strName;

//repeat previous 4 lines for all commands
}


CMainMenuBar::_UpdateMenuBar(BOOL bDoRecalcLayout)
{
BOOL bRet = CExtMenuControlBar::_UpdateMenuBar(bDoRecalcLayout);

//I’m guessing that m_fileOptionLanguage is of type CFile, if not, use the appropiate
CFile m_fileOptionLanguage = reinterpret_cast<CMainFrame *>(AfxGetMainWnd())->GetIniFile();

//change File menu string
UINT nCmdId = m_wndMenuBar.GetButton(0)->GetCmdID();
CExtCmdItem *pCmdItem = g_CmdManager->CmdGetPtr(
g_CmdManager->ProfileNameFromWnd(AfxGetMainWnd()->GetSafeHwnd()),
nCmdId
);
ASSERT( pCmdItem != NULL );
pCmdItem->m_sToolbarText = m_fileOptionLanguage.IniFileReadStringEx("MENU", "ID_MENU_FILE","");

//repeat previous steps for all menus

if( bDoRecalcLayout )
{
Invalidate();
_RecalcLayoutImpl();
UpdateWindow();
}
return bRet;
}

As you can see, you don’t have to use GetMenu() anywhere in the code.

Regards:
Chris