Link to home
Start Free TrialLog in
Avatar of sharpodal
sharpodal

asked on

CMFCMenuBar this does not show the mnemonics

I use the MFC Feature Pack for VS 2008 and use  CMFCMenuBar . This does not show the mnemonics (For example File does not have the _ below File). Do i need to do any specifc setting to make the mnemonics work
BTW, I use the default MFC wizard and the code created is below:
 
 
if (!m_wndMenuBar.Create(this)) 
{ 
TRACE0("Failed to create menubar\n"); 
return -1; // fail to create 
} 
m_wndMenuBar.SetPaneStyle(m_wndMenuBar.GetPaneStyle() | CBRS_SIZE_DYNAMIC | CBRS_TOOLTIPS | CBRS_FLYBY); 
 
  
// prevent the menu bar from taking the focus on activation 
CMFCPopupMenu::SetForceMenuFocus(FALSE); 
  
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) || 
!m_wndToolBar.LoadToolBar(theApp.m_bHiColorIcons ? IDR_MAINFRAME_256 : IDR_MAINFRAME)) 
{ 
TRACE0("Failed to create toolbar\n"); 
return -1; // fail to create 
} 
CString strToolBarName; 
bNameValid = strToolBarName.LoadString(IDS_TOOLBAR_STANDARD); 
ASSERT(bNameValid); 
m_wndToolBar.SetWindowText(strToolBarName); 
CString strCustomize; 
bNameValid = strCustomize.LoadString(IDS_TOOLBAR_CUSTOMIZE); 
ASSERT(bNameValid); 
m_wndToolBar.EnableCustomizeButton(TRUE, ID_VIEW_CUSTOMIZE, strCustomize); 
// Allow user-defined toolbars operations: 
InitUserToolbars(NULL, uiFirstUserToolBarId, uiLastUserToolBarId); 
if (!m_wndStatusBar.Create(this)) 
{ 
TRACE0("Failed to create status bar\n"); 
return -1; // fail to create 
} 
m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT)); 
// TODO: Delete these five lines if you don't want the toolbar and menubar to be dockable 
m_wndMenuBar.EnableDocking(CBRS_ALIGN_ANY); 
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); 
EnableDocking(CBRS_ALIGN_ANY); 
DockPane(&m_wndMenuBar); 
DockPane(&m_wndToolBar); 

Open in new window

Avatar of sharpodal
sharpodal

ASKER

BTW, I use the default MFC wizard and the code created is below:
 
if (!m_wndMenuBar.Create(this))
{
TRACE0("Failed to create menubar\n");
return -1; // fail to create
}
m_wndMenuBar.SetPaneStyle(m_wndMenuBar.GetPaneStyle() | CBRS_SIZE_DYNAMIC | CBRS_TOOLTIPS | CBRS_FLYBY);

 
// prevent the menu bar from taking the focus on activation
CMFCPopupMenu::SetForceMenuFocus(FALSE);
 
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar.LoadToolBar(theApp.m_bHiColorIcons ? IDR_MAINFRAME_256 : IDR_MAINFRAME))
{
TRACE0("Failed to create toolbar\n");
return -1; // fail to create
}
CString strToolBarName;
bNameValid = strToolBarName.LoadString(IDS_TOOLBAR_STANDARD);
ASSERT(bNameValid);
m_wndToolBar.SetWindowText(strToolBarName);
CString strCustomize;
bNameValid = strCustomize.LoadString(IDS_TOOLBAR_CUSTOMIZE);
ASSERT(bNameValid);
m_wndToolBar.EnableCustomizeButton(TRUE, ID_VIEW_CUSTOMIZE, strCustomize);
// Allow user-defined toolbars operations:
InitUserToolbars(NULL, uiFirstUserToolBarId, uiLastUserToolBarId);
if (!m_wndStatusBar.Create(this))
{
TRACE0("Failed to create status bar\n");
return -1; // fail to create
}
m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT));
// TODO: Delete these five lines if you don't want the toolbar and menubar to be dockable
m_wndMenuBar.EnableDocking(CBRS_ALIGN_ANY);
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockPane(&m_wndMenuBar);
DockPane(&m_wndToolBar);


Avatar of Zoppo
Hi sharpodal,

this is one of a lot of bugs within the MFC feature pack - I had the same problem some time ago and found a solution.

There is a trick to get the underlined characters shown (using '&&' instead of '&'), but unfortunateley using this the shortcuts stop working (so i.e. ALT-F doesn't open the 'File' menu anymore).

So, the solution I found is to derive two new classes (one from CMFCMenuBar, i.e. CMyMfcMenuBar, another one derived from CMFCToolBarMenuButton, i.e. CMyMfcMenuButton) as shown in the attached code snippent and then replace the 'CMFCMenuBar m_wndMenuBar' in 'mainfrm.h' with 'CMyMfcMenuBar m_wndMenuBar'.

Hope this helps,

ZOPPO
class CMyMfcMenuButton : public CMFCToolBarMenuButton
{
	/*virtual*/ void OnDraw(
		CDC* pDC,
		const CRect& rect,
		CMFCToolBarImages* pImages,
		BOOL bHorz,
		BOOL bCustomizeMode,
		BOOL bHighlight,
		BOOL bDrawBorder,
		BOOL bGrayDisabledButtons
		)
	{
		CString strSaved = m_strText;
 
		if ( FALSE == m_bMenuMode ) 
		{
			m_strText.Replace( "&", "&&" );
		}
 
		CMFCToolBarMenuButton::OnDraw( pDC, rect, pImages, bHorz, bCustomizeMode, bHighlight, bDrawBorder, bGrayDisabledButtons );
 
		m_strText = strSaved;
	}
};
 
class CMyMfcMenuBar : public CMFCMenuBar
{
public:
	CMyMfcMenuBar()
	: CMFCMenuBar()
	{}
 
	/*virtual*/ int InsertButton( CMFCToolBarButton* pButton, int iInsertAt )
	{
		if (
			FALSE != pButton->IsKindOf( RUNTIME_CLASS( CMFCToolBarMenuButton ) )
			&& FALSE == pButton->IsKindOf( RUNTIME_CLASS( CMFCToolBarSystemMenuButton ) )
			)
		{
			CMyMfcMenuButton *pNewButton = new CMyMfcMenuButton();
 
			pNewButton->CopyFrom( *pButton );
 
			delete pButton;
 
			return CMFCMenuBar::InsertButton( pNewButton, iInsertAt );
		}
 
		return CMFCMenuBar::InsertButton( pButton, iInsertAt );
	}
};

Open in new window

I tried using it. This calls the InsertButton properly in CMyMfcMenuBar but does not call the OnDraw in CMyMfcMenuButton. Do i need to update any thing further. ?
Hm - strange, in my test app it works fine.

I'm not sure, but it might be the formerly saved buttons overwrite this. Try deleting the saved 'Workspace' registry entry for your application (by default it's placed in HKEY_CURRENT_USER\Software\Local AppWizard-Generated Applications\<Your application's name\) - maybe then it works.

Hope that helps,

ZOPPO
I tried the deleting the saved workspace registry and also tried creating one more sample. But OnDraw in CMyMfcMenuButton is not getting called.
Here it the code for the new sample I tried again
Header file SDMenuBar :

#pragma once
 
// CSDMenuBar
class CSDMenuBar : public CMFCMenuBar
{
DECLARE_DYNAMIC(CSDMenuBar)
public:
CSDMenuBar();
virtual ~CSDMenuBar();
virtual int CSDMenuBar:: InsertButton( CMFCToolBarButton* pButton, int iInsertAt );
protected:
DECLARE_MESSAGE_MAP()
};
Implementation of CSDMenuBar

/ SDMenuBar.cpp : implementation file
//
#include "stdafx.h"
#include "MFCMenuTest2.h"
#include "SDMenuBar.h"
#include "SDButton.h"
 
// CSDMenuBar
IMPLEMENT_DYNAMIC(CSDMenuBar, CMFCMenuBar)
CSDMenuBar::CSDMenuBar()
{
}
CSDMenuBar::~CSDMenuBar()
{
}
 
 
int CSDMenuBar:: InsertButton( CMFCToolBarButton* pButton, int iInsertAt )
{
if (
FALSE != pButton->IsKindOf( RUNTIME_CLASS( CMFCToolBarMenuButton ) )
&& FALSE == pButton->IsKindOf( RUNTIME_CLASS( CMFCToolBarSystemMenuButton ) )
)
{
CSDButton *pNewButton = new CSDButton();
pNewButton->CopyFrom( *pButton );

delete pButton;

return CMFCMenuBar::InsertButton( pNewButton, iInsertAt );
}

return CMFCMenuBar::InsertButton( pButton, iInsertAt );

}
BEGIN_MESSAGE_MAP(CSDMenuBar, CMFCMenuBar)
END_MESSAGE_MAP()
 
 
// CSDMenuBar message handlers
---------------------------------------------------------------------------------------------------------------
header file of SDButton

#pragma once
 
// CSDButton
class CSDButton : public CMFCToolBarMenuButton
{
DECLARE_DYNAMIC(CSDButton)
public:
CSDButton();
virtual ~CSDButton();
virtual void OnDraw(CDC* pDC, const CRect& rect, CMFCToolBarImages* pImages, BOOL bHorz = TRUE, BOOL bCustomizeMode = FALSE,
BOOL bHighlight = FALSE, BOOL bDrawBorder = TRUE, BOOL bGrayDisabledButtons = TRUE);
//protected:
// DECLARE_MESSAGE_MAP()
};
 
Implementation of SDButton

// SDButton.cpp : implementation file
//
#include "stdafx.h"
#include "MFCMenuTest2.h"
#include "SDButton.h"
 
// CSDButton
IMPLEMENT_DYNAMIC(CSDButton, CMFCToolBarMenuButton)
CSDButton::CSDButton()
{
}
CSDButton::~CSDButton()
{
}
//BEGIN_MESSAGE_MAP(CSDButton, CMFCToolBarMenuButton)
//END_MESSAGE_MAP()
void CSDButton::OnDraw(CDC* pDC, const CRect& rect,
CMFCToolBarImages* pImages,
BOOL bHorz , BOOL bCustomizeMode ,
BOOL bHighlight ,
BOOL bDrawBorder ,
BOOL bGrayDisabledButtons )
{
CString strSaved = m_strText;

if ( FALSE == m_bMenuMode )
{
m_strText.Replace( L"&", L"&&" );

}

CMFCToolBarMenuButton::OnDraw( pDC, rect, pImages, bHorz, bCustomizeMode, bHighlight, bDrawBorder, bGrayDisabledButtons );

m_strText = strSaved;
}
// CSDButton message handlers
 
And in MainFrame.h changed CMFCMenuBar to CSDMenuBar rest of the code in Mainfram implemenation is as created by Wizard

protected: // control bar embedded members
CSDMenuBar m_wndMenuBar;
CMFCToolBar m_wndToolBar;
CMFCStatusBar m_wndStatusBar;
CMFCToolBarImages m_UserImages;
CFileView m_wndFileView;
CClassView m_wndClassView;
COutputWnd m_wndOutput;
CPropertiesWnd m_wndProperties;
And it's still the same? The buttons are created correctly in InsertButton but the OnDraw isn't called?

Maybe you could ZIP this test project and attach here. My test project just works fine ...
As I have difficulty uploading here as it does not take cpp and h files with the zip, I have uploaded to my public skydrive
at
http://cid-711d4ab54d8e06a5.skydrive.live.com/self.aspx/.Public/MFCMenuTest2.zip
Thanks
ok, I guess I found the problem - it was my mistake: In my test application I had disabled menu-serialization, therefore it works for me.

So, to get your sample working just replace these two statements (in SDButton.h/.cpp):

> DECLARE_DYNAMIC(CSDButton)
> IMPLEMENT_DYNAMIC(CSDButton, CMFCToolBarMenuButton)

with

> IMPLEMENT_DYNAMIC(CSDButton, CMFCToolBarMenuButton)
> IMPLEMENT_SERIAL(CSDButton, CMFCToolBarMenuButton, VERSIONABLE_SCHEMA | 1)

After this delete the above mentioned registry key 'Workspace' for this application (or start your application, use the small arrow at the right of the toolbar to open the 'Customize' dialog, choose 'Menu' tab and press 'Reset').

Now it should work ...

Hope that helps,

ZOPPO
I replaced IMPLEMENT_DYNAMIC(CSDButton, CMFCToolBarMenuButton) with IMPLEMENT_SERIAL(CSDButton, CMFCToolBarMenuButton, VERSIONABLE_SCHEMA | 1)
 
However  replacing  DECLARE_DYNAMIC(CSDButton) with  IMPLEMENT_DYNAMIC(CSDButton, CMFCToolBarMenuButton)
 give lot of compilation errors as it expects DECLARE_SERIAL(CSDButton).

So I replace DECLARE_DYNAMIC(CSDButton)  with DECLARE_SERIAL(CSDButton)  and it compiled OK.
But it still does not call the OnDraw of  
CSDButton and the mnemonics are not visible.

 




Sorry, a typo.

Instead of 'IMPLEMENT_DYNAMIC' it should be 'DECLARE_SERIAL(CSDButton, CMFCToolBarMenuButton)'.

Seems I should try to get more sleep ;o)

ZOPPO
I tried the 'DECLARE_SERIAL(CSDButton, CMFCToolBarMenuButton) but no success yet. Am i missing some thing more.
ASKER CERTIFIED SOLUTION
Avatar of Zoppo
Zoppo
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I had to delete the workspace again and it worked. Thanks a lot.
Thank You very much for your prompt reply and support
That's fine - I'm glad I could help ...

Unfortunateley as told above using the MFC FeaturePack IMO often needs to workaround bugs or inconsistent implemented or strange designed implementations. Further the documentation is a mess.

I migrated a GUI intensive application from MS VC++ 6 with 'old' MFC to MS VS 2008 with 'new' MFC FeaturePack - just to get the GUI working as before I had to write about 7000 lines of code and had to overwrite functionalities in about 20 MFC classes.

The only good thing for this is that all sources are available, with a little bit experience it's not too hard to find why something doesn't work as expected.

I wish you luck with your project ...

Best regards,

ZOPPO
Thank You ! Once again