I have a MDI program that is setup to support multiple languages. This app is configured to allow the operator to swap the language on-the-fly and all the menus/dialogs/etc will automatically switch to the newly selected language.
There are multiple types of document / view classes, and each class has its own menu. Also, I have a function that will return the translation (for the selected language) that is keyed off of the operator specified language.
Everything works fine when I have only 1 document open, but if there are 2 documents, then the program crashes (because GetSubMenu returns a NULL) when I switch to the 2nd document.
Each CScrollView type that I have uses a function such as OnActivateView bellow...
Code:
void CDocType1View::OnActivateView(BOOL bActivate, CView* pActivateView, CView* pDeactiveView)
{
if (bActivate)
MainFramePtr->ShowType1Tools(); // changes the toolbar just bellow the menu
CScrollView::OnActivateView(bActivate, pActivateView, pDeactiveView);
if (bActivate && (nPrevLang != larray.nLangIdx))
RebuildMenu();
}
nPrevLang is a private int variable for CDocType1View
larray is a structure containing all my translations, a function "L" that return the translated text, and nLangIdx which keeps track of the selected language
The problem is in RebuildMenu(), when I first assign submenu2 (in the "Edit" section)...
Code:
void CDocType1View::RebuildMenu()
{
if (nPrevLang == larray.nLangIdx)
return;
nPrevLang = larray.nLangIdx;
CMenu *pMenu = AfxGetApp()->m_pMainWnd->GetMenu(),
*submenu = NULL,
*submenu2 = NULL,
*submenu3 = NULL,
*submenu4 = NULL;
CString szTemp;
// File
submenu = pMenu->GetSubMenu(0);
szTemp = larray.L(_T("&File"));
pMenu->ModifyMenu(0, MF_BYPOSITION, MF_STRING, szTemp);
szTemp = larray.L(_T("&Open...\tCtrl O"));
submenu->ModifyMenu(ID_FILE_OPEN, MF_BYCOMMAND, ID_FILE_OPEN, szTemp);
szTemp = larray.L(_T("&Print...\tCtrl P"));
submenu->ModifyMenu(ID_FILE_PRINT, MF_BYCOMMAND, ID_FILE_PRINT, szTemp);
szTemp = larray.L(_T("Print Pre&view"));
submenu->ModifyMenu(ID_FILE_PRINT_PREVIEW, MF_BYCOMMAND, ID_FILE_PRINT_PREVIEW, szTemp);
szTemp = larray.L(_T("P&rint Setup..."));
submenu->ModifyMenu(ID_FILE_PRINT_SETUP, MF_BYCOMMAND, ID_FILE_PRINT_SETUP, szTemp);
szTemp = larray.L(_T("E&xit"));
submenu->ModifyMenu(ID_APP_EXIT, MF_BYCOMMAND, ID_APP_EXIT, szTemp);
// Edit
submenu = pMenu->GetSubMenu(1);
szTemp = larray.L(_T("&Edit"));
pMenu->ModifyMenu(1, MF_BYPOSITION, MF_STRING, szTemp);
szTemp = larray.L(_T("Change Co&mments\tQ"));
submenu->ModifyMenu(ID_EDIT_CHANGECOMMENTS, MF_BYCOMMAND, ID_EDIT_CHANGECOMMENTS, szTemp);
submenu2 = submenu->GetSubMenu(1);
// this is where I'm failing on the 2nd document initialization, GetSubMenu return NULL
szTemp = larray.L(_T("Grouping"));
submenu->ModifyMenu(1, MF_BYPOSITION, MF_STRING, szTemp);
szTemp = larray.L(_T("Group 1"));
submenu2->ModifyMenu(ID_EDIT_GROUP1, MF_BYCOMMAND, ID_EDIT_GROUP1, szTemp);
szTemp = larray.L(_T("Group 2"));
submenu2->ModifyMenu(ID_EDIT_GROUP2, MF_BYCOMMAND, ID_EDIT_GROUP2, szTemp);
submenu2 = submenu->GetSubMenu(2);
szTemp = larray.L(_T("Typing"));
submenu->ModifyMenu(2, MF_BYPOSITION, MF_STRING, szTemp);
szTemp = larray.L(_T("Type 1"));
submenu2->ModifyMenu(ID_EDIT_TYPE1, MF_BYCOMMAND, ID_EDIT_TYPE1, szTemp);
szTemp = larray.L(_T("Type 2"));
submenu2->ModifyMenu(ID_EDIT_TYPE2, MF_BYCOMMAND, ID_EDIT_TYPE2, szTemp);
// ... I have clipped the rest of the code between the "Edit->Typing" through "Help", but it is very similar in style and substance. There are more cascades of menus that require me to use 4 submenu pointers.
// Help
submenu = pMenu->GetSubMenu(5);
szTemp = larray.L(_T("&Help"));
pMenu->ModifyMenu(5, MF_BYPOSITION, MF_STRING, szTemp);
szTemp = larray.L(_T("&Help Topics"));
submenu->ModifyMenu(ID_HELP_FINDER, MF_BYCOMMAND, ID_HELP_FINDER, szTemp);
szTemp = larray.L(_T("&About Display..."));
submenu->ModifyMenu(ID_APP_ABOUT, MF_BYCOMMAND, ID_APP_ABOUT, szTemp);
}
Can anyone tell me why this is failing when I switch to my 2nd document / view?
I'd suggest you to redesign...
It's a very bad idea to hard code the texts (not only for menus!). You should just load the menu for appropriate language and destroy the existent one after you changed the language.
The translations are not hard coded. There is a database that the operator is able to modify so that they can have their own "custom" translations if need be. Because of that, I can't really create separate resources for different languages... there are far too many possibilities and I would have to re-deploy any time someone wanted to tweak their wording.
If it were me then, I'd probably set up the CCmdUI update mechanism, call GetText() when it's about to display, look up the value in the database then use SetText() to display the command in the correct language.
If it were me then, I'd probably set up the CCmdUI update mechanism, call GetText() when it's about to display, look up the value in the database then use SetText() to display the command in the correct language.
Wouldn't that just update the text once you mouse over? I want the text to change as soon as the operator changes from English -> Spanish (etc.), not when they actually go through the menu system.
Wouldn't that just update the text once you mouse over? I want the text to change as soon as the operator changes from English -> Spanish (etc.), not when they actually go through the menu system.
It would change the text whenever the menu item was about to be displayed. It's not necessary to change the text on items they can't see. All you'd need to do is have the correct database or translation table in place and the OnUpdate handler would ensure the correct text was displayed whenever necessary.
Each CScrollView type that I have uses a function such as OnActivateView bellow...
Code:
void CDocType1View::OnActivateView(BOOL bActivate, CView* pActivateView, CView* pDeactiveView)
{
if (bActivate)
MainFramePtr->ShowType1Tools(); // changes the toolbar just bellow the menu
CScrollView::OnActivateView(bActivate, pActivateView, pDeactiveView);
if (bActivate && (nPrevLang != larray.nLangIdx))
RebuildMenu();
}
Why don't you check the view to be activated? (it sounds like you are trying to RebuildMenu for the deactivated view too!)
Why don't you check the view to be activated? (it sounds like you are trying to RebuildMenu for the deactivated view too!)
Isn't this what I'm doing in "OnActivateView" right before the call to "RebuildMenu"? I would think that the condition of bActivate == TRUE would take care of this.
Originally Posted by vandy_mike
Code:
void CDocType1View::OnActivateView(BOOL bActivate, CView* pActivateView, CView* pDeactiveView)
{
if (bActivate)
MainFramePtr->ShowType1Tools(); // changes the toolbar just bellow the menu
CScrollView::OnActivateView(bActivate, pActivateView, pDeactiveView);
if (bActivate && (nPrevLang != larray.nLangIdx))
RebuildMenu();
}
Isn't this what I'm doing in "OnActivateView" right before the call to "RebuildMenu"? I would think that the condition of bActivate == TRUE would take care of this.
No.
You should also check the (pActivateView == this) condition.
Bookmarks