Click here to Skip to main content
Click here to Skip to main content

Cool Owner Drawn Menus with Bitmaps - Version 3.03

By , 28 Apr 2002
 

What's new in Version 3.01

As you can see I've added the new Office XP drawing style for the menu's. I just got a machine with Windows XP on it and I noticed that the menu's in all our applications looked terrible. So I decided to do something about it and after 2 years of not looking at the class, added the new menu drawing style, and added lot's of fixes and user requests. Now the new drawing style isn't exactly like Microsoft's, but I got it so it looks good enough to me. For people that use the old class it's a simple matter of taking exchanging the old BCMenu .cpp and .h files with the new ones.

The class currently uses the new style on XP and the old style on Win9x/NT and 2000. However, if you like the new style and you want to use it on all Windows platforms, just change the following line at the top of the BCMenu.cpp file from:

UINT BCMenu::original_drawmode=BCMENU_DRAWMODE_ORIGINAL;

to

UINT BCMenu::original_drawmode=BCMENU_DRAWMODE_XP;

Likewise, if you think I did a terrible job you can change the drawing style to the original one on all the platforms.

Other additions include support for images with greater than 16 colors. The example contains images with both 256 and 16 million colors. There is also an option for how to draw disabled options. In XP mode they are not selected but this can be changed. I also fixed the problem with multiple menu items with the same command ID not getting images (only the first one did!). See the bottom of this article for more information on updates.

Introduction

This class, BCMenu, implements owner drawn menus derived from the CMenu class. The purpose of which is to mimic the menu style used in Visual C++ 5.0 and MS Word. I can't take credit for all the code, some portions of it were taken from code supplied by Ben Ashley and Girish Bharadwaj. The difference between their codes and this one is quite simple, this one makes it very easy to build those cool menus with bitmaps into your application. I've removed the Icon loading stuff and replaced it with Bitmaps. The bitmaps allow you to use the 16X15 toolbar bitmaps directly from your toolbars in the resource editor. As well, there is no scaling of the bitmaps so they always look good. You can also load Bitmap resources and define bitmaps for your check marks. I've also added the default checkmark drawing stuff, separators, proper alignment of keyboard accelerator text, keyboard shortcuts, proper alignment of popup menu items, proper system color changes when the Display Appearance changes, plus bug fixes to the Ben Ashley's LoadMenu function for complex submenu systems. I made quite a few other modifications as well, too many to list or remember. I also use the disabled bitmap dithering function of Jean-Edouard Lachand-Robert to create the disabled state bitmaps. I must admit, it does a much better job then the DrawState function. If you find any bugs, memory leaks, or just better ways of doing things, please let me know. I used Visual C++ 5.0 and I have not tested compatibility with earlier VC versions. I've tested it on Win 95/NT at various resolutions and color palette sizes.

Installation (MDI Application)

Well, enough of the boring stuff, lets talk about implementation. To make it easy I'm first going to list step by step the method for implementing the menus into a MDI application:

  1. Create your MDI application using the App Wizard.
  2. Insert the BCMenu.cpp and BCMenu.h files into your Workspace.
  3. Add the following public member functions to your CMainFrame class in the MainFrm.h header file:
    HMENU NewMenu();
    HMENU NewDefaultMenu();
  4. Add the following public member variables to your CMainFrame class in the MainFrm.h header file:
    BCMenu m_menu,m_default;
  5. Add the line:
    #include "BCMenu.h"

    to the top of the MainFrm.h header file.

  6. Open the Mainfrm.cpp implementation file and add the NewMenu and NewDefaultMenu member functions as listed below. IMPORTANT: Make sure you replace the IDR_MYMENUTYPE menu id in the below LoadMenu call to the menu id associated with the menu's in your application. Look in the menus folder of the Resources view.
    HMENU CMainFrame::NewMenu()
    {
      static UINT toolbars[]={
          IDR_MAINFRAME
      };
    
      // Load the menu from the resources
      // ****replace IDR_MENUTYPE with your menu ID****
      m_menu.LoadMenu(IDR_MYMENUTYPE);  
      // One method for adding bitmaps to menu options is 
      // through the LoadToolbars member function.This method 
      // allows you to add all the bitmaps in a toolbar object 
      // to menu options (if they exist). The first function 
      // parameter is an array of toolbar id's. The second is 
      // the number of toolbar id's. There is also a function 
      // called LoadToolbar that just takes an id.
      m_menu.LoadToolbars(toolbars,1);
    
      return(m_menu.Detach());
    }
    
    HMENU CMainFrame::NewDefaultMenu()
    {
      m_default.LoadMenu(IDR_MAINFRAME);
      m_default.LoadToolbar(IDR_MAINFRAME);
      return(m_default.Detach());
    }
    
  7. Edit the InitInstance member function of your CWinApp derived class and add following highlighted code in the position noted:
    // create main MDI Frame window
    CMainFrame* pMainFrame = new CMainFrame;
    if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
       return FALSE;
    m_pMainWnd = pMainFrame;
    
    // This code replaces the MFC created menus with 
    // the Ownerdrawn versions 
    pDocTemplate->m_hMenuShared=pMainFrame->NewMenu();
    pMainFrame->m_hMenuDefault=pMainFrame->NewDefaultMenu();
    
    // This simulates a window being opened if you don't have
    // a default window displayed at startup
    pMainFrame->OnUpdateFrameMenu(pMainFrame->m_hMenuDefault);
    
    // Parse command line for standard shell commands, 
    // DDE, file open
    CCommandLineInfo cmdInfo;
    ParseCommandLine(cmdInfo);
    
  8. Add the message handlers for the WM_MEASUREITEM, WM_MENUCHAR, and WM_INITMENUPOPUP messages to your CMainFrame class. Do this by right clicking on the CMainFrame class in the ClassView and selecting Add Windows Message Handler. Choose the Window option from the Filter for messages available to class combo box. Select the message and add the handler. Then edit the handler and add the below code.
    //This handler ensure that the popup menu items are 
    // drawn correctly
    void CMainFrame::OnMeasureItem(int nIDCtl, 
     LPMEASUREITEMSTRUCT lpMeasureItemStruct) 
    {
      BOOL setflag=FALSE;
      if(lpMeasureItemStruct->CtlType==ODT_MENU){
        if(IsMenu((HMENU)lpMeasureItemStruct->itemID)){
          CMenu* cmenu = 
           CMenu::FromHandle((HMENU)lpMeasureItemStruct->itemID);
    
          if(m_menu.IsMenu(cmenu)||m_default.IsMenu(cmenu)){
            m_menu.MeasureItem(lpMeasureItemStruct);
            setflag=TRUE;
          }
        }
      }
    
      if(!setflag)CMDIFrameWnd::OnMeasureItem(nIDCtl, 
                                              lpMeasureItemStruct);
    }
    
    //This handler ensures that keyboard shortcuts work
    LRESULT CMainFrame::OnMenuChar(UINT nChar, UINT nFlags, 
     CMenu* pMenu) 
    {
      LRESULT lresult;
      if(m_menu.IsMenu(pMenu)||m_default.IsMenu(pMenu))
        lresult=BCMenu::FindKeyboardShortcut(nChar, nFlags, pMenu);
      else
        lresult=CMDIFrameWnd::OnMenuChar(nChar, nFlags, pMenu);
      return(lresult);
    }
    
    //This handler updates the menus from time to time
    void CMainFrame::OnInitMenuPopup(CMenu* pPopupMenu, 
     UINT nIndex, BOOL bSysMenu) 
    {
      CMDIFrameWnd::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);
      if(!bSysMenu){
        if(m_menu.IsMenu(pPopupMenu)||m_default.IsMenu(pPopupMenu))
          BCMenu::UpdateMenu(pPopupMenu);
      }
    }
    
  9. If you are debugging or you are mixing standard menus with the BCMenu's (maybe you have different Document templates using the standard menu's) then you should turn on RTTI in the project settings.

Well, that's it. Compile the program and look in the File menu. You should see the bitmaps. I've tried the menus with context menus and they seem to work fine.

Installation (SDI Application)

  1. Create your SDI application using the App Wizard.
  2. Insert the BCMenu.cpp and BCMenu.h files into your Workspace.
  3. Add the following public member function to your CMainFrame class in the MainFrm.h header file:
    HMENU NewMenu();
    </tt />
  4. Add the following public member variables to your CMainFrame class in the MainFrm.h header file:
    BCMenu m_menu;
    </tt />
  5. Add the line:
    #include "BCMenu.h"</tt />

    to the top of the MainFrm.h header file.

  6. Open the Mainfrm.cpp implementation file and add the NewMenu and NewDefaultMenu member functions as listed below. IMPORTANT: Make sure you replace the IDR_MAINFRAME menu id in the below LoadMenu call to the menu id associated with the menu's in your application. Look in the menus folder of the Resources view.
    HMENU CMainFrame::NewMenu()
    {
      // Load the menu from the resources
     // ****replace IDR_MAINFRAME with your menu ID****
      m_menu.LoadMenu(IDR_MAINFRAME);  
     // One method for adding bitmaps to menu options is 
     // through the LoadToolbar member function.This method 
     // allows you to add all the bitmaps in a toolbar object 
     // to menu options (if they exist). The function parameter 
     // is an the toolbar id. There is also a function called 
     // LoadToolbars that takes an array of id's.
      m_menu.LoadToolbar(IDR_MAINFRAME);
    
      return(m_menu.Detach());
    }
    
  7. Edit the InitInstance member function of your CWinApp derived class and add following highlighted code in the position noted:
      // Dispatch commands specified on the command line
      if (!ProcessShellCommand(cmdInfo))
         return FALSE;
    
      CMenu* pMenu = m_pMainWnd->GetMenu();
      if (pMenu)pMenu->DestroyMenu();
      HMENU hMenu = ((CMainFrame*) m_pMainWnd)->NewMenu();
      pMenu = CMenu::FromHandle( hMenu );
      m_pMainWnd->SetMenu(pMenu);
      ((CMainFrame*)m_pMainWnd)->m_hMenuDefault = hMenu;
    </tt />
  8. Add the message handlers for the WM_MEASUREITEM, WM_MENUCHAR, and WM_INITMENUPOPUP messages to your CMainFrame class. Do this by right clicking on the CMainFrame class in the ClassView and selecting Add Windows Message Handler. Choose the Window option from the Filter for messages available to class combo box. Select the message and add the handler. Then edit the handler and add the MDI code from above. Replace the references to CMDIFrameWnd to CFrameWnd.
  9. If you are debugging or you are mixing standard menus with the BCMenu's (maybe you have different Document templates using the standard menu's) then you should turn on RTTI in the project settings.

Improvements and Bug Fixes

Version 3.03

  1. Completely changed the way the bitmaps are stored. To improve resource memory management on Win9x platforms I moved to a single image list for all bitmaps. No longer does every menu option store a CImageList object for the bitmap. People will notice a drop in GDI object utilization under all platforms.

  2. Improved the disabled embossed look for XP menu's.
  3. Fixed up the large toolbar size bitmaps. Must use SetIconSize before doing anything with the bitmaps larger than 16X15.
  4. Fixed up the reading of hi-color bitmaps. Now properly disables and displays them as long as you use the standard RGB(192,192,192) as the background color.
  5. Checkmarks look more like Office XP.
  6. Separators don't take up as much space in XP look.
  7. Can now turn change the way the right justification of the accelerators works. You can get the more condensed look (yuk!) that MS uses by simply changing the xp_space_acclerators and original_space_accelerators values from TRUE to FALSE in the BCMenu.cpp file.

Version 3.01

  1. The Office XP menus can be displayed with a 3D pop-out look. Basically the icons have a faded look until the menu option is selected. When selected they are drawn with a 3D shadow in their full glorious color. If you don't like this look (some people I know do and some don't) then you can easily turn it off by setting the BOOL BCMenu::xp_draw_3D_bitmaps variable to FALSE in the BCMenu.cpp file.
  2. Added DECLARE_DYNAMIC/IMPLEMENT_DYNAMIC to the class so that I could use IsKindOf. This solves some problems of the class inadvertently trying to delete CMenu objects. It also makes it easier to add menu options to the top level menubar. See the MDI example for how to do this.
  3. Fixed problems with the fonts and default menu options.
  4. Improved how the class tests for running under XP Luna. This fixes some problems that the 3.0 class had when people used funky desktop color schemes.
  5. Changed how the menu responds to a change in the system menu color. The original menu's get colored with the menu color while the XP menu's get colored with the window color. This is how MS does it. The only exception is the original look on WinXP Luna. Since I hate white menu's I use the 3D color instead. This seems to be what Developer Studio does. Basically MS has no policy on menu color on WinXP Luna so I'm making it up as I go.
  6. Added a MFC Dialog based example. I got tired of people asking how to do it. It's actually quite easy. You basically do all the same stuff as you do in an MDI app. You define an instance of BCMenu in your CDialog derived class and override the menu in the OnInitDialog using SetMenu. Then handle the windows messages OnMenuChar,OnInitMenuPopup,and OnMeasureItem as you do in an MDI app. Make sure you DestroyMenu the class in an OnClose handler. The only issue I found, that's unrelated to the class, is the behavior of the OnUpdate CCmdUI stuff. It's not done the same way as in an MDI app. The OnUpdates are not called when a OnInitMenuPopup message is handled. So I made it behave the same way by grabbing a chunk from CFrameWnd::OnInitMenuPopup and putting it in my Dialog's OnInitMenuPopup handler. If anyone knows a better way, please let me know.

Version 3.0

  1. Added Office XP drawing style.
  2. Added support for menu images with greater than 16 colors.
  3. Can set whether disabled menu options can be selected.
  4. Improved the memory storage of the images. The entire toolbar image is no longer stored for a menu option.
  5. Added a SetMenuText method.
  6. Added a RemoveMenu function that takes the popup menu title instead of it's location.
  7. Added a GetSubMenu function that returns a pointer to the menu.
  8. Fixed the problem with only the first of multiple menu options with the same command id getting an image.
  9. InsertMenu now takes -1 for the position and properly appends the option to the end of the menu.
  10. Fixed the problem with RichEditViews
  11. If the menu option was given a checked state in the resource editor it wasn't getting applied. Fixed.
  12. Reformatted and improved the class layout.

Version 2.63

  1. RemoveMenu/DeleteMenu with popups asserts, this has been fixed.
  2. Updated the example.

Version 2.62

  1. There were some problems with dynamically adding and removing separators.
  2. InsertMenu using the MF_BYCOMMAND flag didn't work correctly.

Version 2.61

  1. The ImageListDuplicate function was always being called with an offset of 0 instead of the user defined offset.
  2. The ImageListDuplicate function was improved. It now handles 16X16 bitmaps and can handle more color depth.
  3. User information can now be tagged on to a menu item through the pContext BCMenuData member variable.
  4. A FindMenuItem function is added to allow you to retrieve menu data using a command id.
  5. A m_bDynIcons member variable has been added. If it is set to TRUE then resource id's are loaded as Icons instead of bitmaps.

Version 2.6

  1. Version 2.5 was not VC++ 5.0 compatible. I had used a CImageList::Create( CImageList* pImageList ); overload that isn't available in 5.0. The above overload also calls a SDK function that is not supported in Windows 95 without IE 4.0. As a result, the menu class would crash if you use any of the menu functions that add a bitmap through a CBitmap or CImageList object. All is now fixed!

Version 2.5

  1. Added support for dynamically created menu's. The new functions include:
    • BOOL RemoveMenu(UINT uiId,UINT nFlags);
    • BOOL DeleteMenu(UINT uiId,UINT nFlags);
    • BOOL AppendMenu(UINT nFlags,UINT nIDNewItem,const char *lpszNewItem,int nIconNormal=-1);
    • BOOL AppendMenu(UINT nFlags,UINT nIDNewItem,const char *lpszNewItem,CImageList *il,int xoffset);
    • BOOL AppendMenu(UINT nFlags,UINT nIDNewItem,const char *lpszNewItem,CBitmap *bmp);
    • BOOL InsertMenu(UINT nPosition,UINT nFlags,UINT nIDNewItem,const char *lpszNewItem,int nIconNormal=-1);
    • BOOL InsertMenu(UINT nPosition,UINT nFlags,UINT nIDNewItem,const char *lpszNewItem,CImageList *il,int xoffset);
    • BOOL InsertMenu(UINT nPosition,UINT nFlags,UINT nIDNewItem,const char *lpszNewItem,CBitmap *bmp);
    See the example for details on implementation. You can define the bitmap for the appended or inserted menu item using a resource id, CBitmap object or a CImageList object.
  2. Added new functions:
    • BCMenu* AppendODPopupMenuA(LPCSTR lpstrText); - A simple method for dynamically adding a popup menu.
    • BOOL ModifyODMenuA(const char *lpstrText,UINT nID,CImageList *il,int xoffset);
    • BOOL ModifyODMenuA(const char *lpstrText,UINT nID,CBitmap *bmp);
  3. Can now define the bitmap using a Cbitmap object or a CImageList object
  4. BCMenu now maintains a list of every BCMenu created. Using the now static member function BCMenu::Ismenu you can easily determine if a menu is a BCMenu.
  5. A few resource leaks were fixed.

Version 2.4

  1. Updated the code to work with VC++ 6.0. Fixed the GetMenuItemInfo problem.
  2. If a tab character existed in every menu option there was a problem with the InsertSpaces function.
  3. The FindMenuOption would not find a popup menu option if it was in a popup itself.
  4. Initialization was added for pFont and nID.

Version 2.3 (courtesy of Stefan Kuhr)

  1. Conversions from Unicode to ANSI and vice versa are now being made through the helper macros described in MFC Tech Note 059. Memory allocations for the conversions are now being made primarily on the stack, which is much safer and faster on Win32 than on the heap. And the code looks much better and shorter.
  2. The Unicode String in the BCMenuData is now to be allocated on the heap thus having only the memory footprint it needs to have. BCMenuData has new member functions for accessing the now private String variable wchar_t *m_szMenuText.
  3. Corrected a few situations in BCMenu code where portable constant strings (_T()) should be used.
  4. Improved look on the old shell. It really looks nice now on WinNT 3.51 and Win32s. You can now run the sample on NT3.51.
  5. The function 'IsNewShell' is now replaced by 'IsShellType'. BCMenu has a new static member function BOOL IsNewShell(void).
  6. Added Unicode project settings to the sample.
  7. Changed strings in the sample to portable versions by use of the _T() macro.
  8. Set warning level of all project settings in the sample to the highest level (W4) and corrected everything to compile cleanly without any warning being thrown by VC 5.

Version 2.2

  1. Fixed a memory leak in AddBitmapToImageList. This only affected floating popup menu's (right mouse button).

Version 2.1

  1. Was not deleting the disabled bitmap in DrawItem causing a resource leak. This has been fixed.

Version 2.0

  1. Version 1.9 had some problems with the new disabled look under different desktop color schemes. This has been fixed.
  2. There was a bug in the image list stuff. For non-default desktop color schemes, the 3D colors were not being done correctly to match the toolbar.

Version 1.9

  1. The disabled look of the menu icons now match the disabled look of the toolbar buttons in Joerg Koenig's flat toolbar class available from http://www.codeproject.com/menu/<font%20color=#008000>//www.codeguru.com/. If you prefer the old look you can get it back through a call to the SetDisableOldStyle member function.

Version 1.8

  1. Made a modification to support OCX controls.

Version 1.7

  1. Added UNICODE and Win32s old shell support (WIN 3.1 and WINNT 3.5).
  2. Added integrated radio and checked buttons.
  3. Now using AfxLoadSysColorBitmap to load the bitmaps.
  4. Now using the WM_INITMENUPOPUP message handler to update the menus instead of the OnUpdateWindowNew.

Version 1.6

  1. Multiple LoadMenu/DestroyMenu combinations crashed. This has been fixed.

Version 1.5

  1. Can now easily add bitmaps to popup options. See the CMainFrame::Newmenu member function in the sample application for implementation instructions.
  2. The UpdateMenu member function will now work to update menu's after a dynamic change in the menu's options text.

Version 1.4

  1. More work on the sizing and position of Accelerator text on menus.

Version 1.3

  1. Keyboard shortcuts did not work correctly with the active view menu options in the MDI Window popup.
  2. Keyboard shortcuts did not work correctly with the most-recently-used (MRU) file list. Menu options after this list could not be selected with keyboard shortcuts.
  3. For some reason MFC treats MeasureItem results differently for first level popups. The expanded tabs size calculation (GetTabbedTextExtent) works well for submenus but MFC seems to pad too much space onto the first level popups. I tried to be smart and reduce the size manually, but this messed up submenus. I've gone back to the original tabbed size calculation in MeasureItem.

Version 1.2

  1. The memory used to store the checkmark bitmaps was not being released when the menu was destroyed. This resulted in a memory leak. This has been fixed.
  2. Added the AddFromToolBar member function for loading all the bitmaps from a toolbar into menu options (if they exist). If you want ALL the bitmaps from a toolbar to be mapped to menu options, use this function. This replaces the many ModifyODMenu function calls that you would have to make. If you only want a few of the toolbar options mapped to menu options then you have to use the ModifyODMenu method.

Version 1.1

  1. When the user typed a keyboard shortcut that didn't exist the program crashed.
  2. The first item, if it contained a bitmap, was not drawn correctly when keyboard shortcuts were used.
  3. Large fonts caused some alignment problems, this has been fixed.
  4. The AppendODMenu and ModifODMenu member functions were prototyped incorrectly.
  5. The LoadMenu(LPCTSTR lpszResourceName) overloaded member function didn't work.
  6. Added RTTI checking in the code if it's defined in the project Settings. This is both helpful for debugging and is required if you mix standard menus with BCMenu's.
  7. Added Word 97 radio button style for checked menu options with bitmaps.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Brent Corkum
Web Developer
Canada Canada
Member
I'm the senior software development manager for Rocscience Inc., a company specializing in geomechanics software. I have a PH.D in Civil Engineering, and have been programming since 1978. I've used more computers and languages then 2000 characters lets me list. Besides programming, I enjoy golfing, watching my 3 kids play sports, spending time with my wife, and watching plenty of hockey and football.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralRe: Odd behaviour - WM_MEASUREITEMmemberllox13 Dec '10 - 23:19 
Problem is more or less solved..
I still get the warnings that confuse me, but the visualisation error is gone.
What went wrong: mixing release-mode compilation of my application with a debug-mode compilation of the OCX-control doesn't do any good Wink | ;)
After registering the release-mode comp. everything works fine..
GeneralRe: Odd behaviour - WM_MEASUREITEMmemberllox19 Jan '11 - 21:34 
Hmm... Well, the problem is still existant, but vice versa:
I compiled the ocx in release mode and gave it for implementation to a colleague. He - of course - compiles his program in debug mode. But if he tries to open the context menu, he gets a debug assertion..
Any hint would be appreciated! Smile | :)
GeneralMy vote of 2memberyourlin24 Oct '10 - 22:33 
Can't work in VS 2008, crashed when m_menu.LoadMenu(IDR_MYTYPE);
Generalsize problem if using Icon only (without text)membermimosa22 Jun '10 - 18:58 
Hi
this is a very nice class. My icons appear very nicely. However, I want to use icon only, and remove the text, so I use:
 
menuView.SetMenuText(MY_MENU_COMMAND,"",MF_BYCOMMAND);
 
There are no more text, but there is a little gap on the right of the icon. How can I get ride of it?
 
Thanks!
Mat Suspicious | :suss:

GeneralRussian textmemberandrewtruckle4 Nov '09 - 10:33 
I find the menu crops if I am using Russian text (in English windows).
 
Andrew
QuestionMenuItem(menu bar) did not trigger DrawItem - BUG ??memberkarhong29 Dec '08 - 21:58 
Hi, when i tried this owner draw menu, why did the DrawItem function are not being triggered??
Because when i tried other owner draw menu, even if i did not click the menu item[on the menu bar] it will trigger the DrawItem.
 
I'm trying to change the font's color of the menu item text[on the menu bar]
I already succeeded to change the font color of the submenu items.. which it will trigger DrawItem function when i click it.
 
is that a bug or ??
 
Regards,
KH
 
good

GeneralMenu size problem after changing the menu textmemberBrad Kremer19 Jun '08 - 9:57 
I used the BCMenu in my application, and it worked great. That was until I changed the menu text. My application can change languages on the fly.
 
I start my application in one language and set all the menu text. OnMeasureItem gets called to get the size of each menu as I use it. It will never be called again. I then change languages and change all the menu text. The problem is the menu sizes don't fit the new text.
 
I figured a way to fool windows into thinking that the menu text changed. It requires three extra lines in BCMenu.cpp:SetMenuText function. I'm using BCMenu 3.036
 
Hopefully this will help if anyone else is having trouble with this problem.
 
BOOL BCMenu::SetMenuText(UINT id, CString string, UINT nFlags/*= MF_BYPOSITION*/ )
{
	BOOL returnflag=FALSE;
	
	if(MF_BYPOSITION&nFlags)
	{
		UINT numMenuItems = m_MenuList.GetUpperBound();
		if(id<=numMenuItems){
#ifdef UNICODE
			m_MenuList[id]->SetWideString((LPCTSTR)string);
#else
			m_MenuList[id]->SetAnsiString(string);
#endif
			returnflag=TRUE;
		}
		<code>//BK: this forces windows to get the menu dimensions again after changing the menu text
		int id2 = GetMenuItemID(id);  //id in this case is the position
		if (id2 != 0 && id2 != -1)
			ModifyMenu(id, MF_BYPOSITION, id2, ""); //no text needed as it's owner-drawn
		//BK: end of changes</code>
	}
	else{
		int uiLoc;
		BCMenu* pMenu = FindMenuOption(id,uiLoc);
		if(NULL!=pMenu) returnflag = pMenu->SetMenuText(uiLoc,string);
	}
	return(returnflag);
}

GeneralRe: Menu size problem after changing the menu textmembermimosa22 Jun '10 - 18:56 
Your code makes my icon to disapear...
Mat Suspicious | :suss:

GeneralOdd behavior when I try to remove using this classmemberandrewtruckle21 May '08 - 4:27 
Hello
 
I decided I wanted to try try and use the native CMenu objects again for my MDI IDR_MAINFRAME in my project.
 
So I remmed out the two lines of code in my InitInstance class which indicated would revert it back to normal.
 
However, when I do this, I find the last but one menu refuses to display. I get no crashes. If I add further menus, then it will display. Only the last but one refuses to show.
 
If I put the two lines back into InitInstance, the menu fully operations.
 
I have trie dremoving BCMenu completely from my project and I still get this behavior.
 
Ideas?
GeneralRe: Odd behavior when I try to remove using this classmemberandrewtruckle21 May '08 - 4:32 
Hhhmm. If I also rem this out:
 
//pMainFrame->OnUpdateFrameMenu(pMainFrame->m_hMenuDefault);
 
I get a complete old style menu again - fully operational.
QuestionproblemmemberAAAzhanglei19 Apr '08 - 23:17 
Hi,Brent Corkum
Thank you for your work.I can not add a icon int the menuitem,can you help me?of course i could convert a bitmap to icon,but you know ,it is not easy ,I was a beginner of vc 6.0,your answer is important to me,could you give me a complete reference of BCMenu if you have . I think I could learn more easy than before .Thank You!!Email zhangleibaobaoz@163.com
Generalproblem in vs2008 (vc++)memberMember 18428549 Apr '08 - 23:29 
I compiled the demo program in vs2008 and there is no error.
However, when I execute the program, there is one problem occurred.
The program cannot be executed on the following line in void BCMenu::InsertSpaces().
VERIFY (SystemParametersInfo (SPI_GETNONCLIENTMETRICS,nm.cbSize,&nm,0));
GeneralRe: problem in vs2008 (vc++)memberMember 18428549 Apr '08 - 23:47 
I answer by myself.
The problem is the same as NewMenu.
I should assign the correct WINVER.
Please see below.
---------------------------------
Probably you did not set the right WINVER versionsnumber and the size of NONCLIENTMETRICS will be wrong for XP (Vista will be ok)
 
=> If the function fails, the return value is zero. To get extended error information, call GetLastError.
 
Check this output!
#pragma message(" WINVER not defined. Defaulting to 0x0600 (Windows Vista)")
 
Windows Vista:
#define WINVER 0x0600
 
Windows Server 2003 SP1, Windows XP SP2
#define WINVER 0x0502
 
Windows Server 2003, Windows XP
#define WINVER 0x0501
 
Windows 2000
#define WINVER 0x0500
QuestionDoes it compile on VC++ 2005?memberandrewtruckle12 Feb '08 - 4:42 
Andrew
GeneralRe: Does it compile on VC++ 2005?memberAndrew Athiou18 Feb '08 - 2:17 
Yes it does compile with VC++ 2005. I think you may have problems with VC++ 2008 though.
GeneralRe: Does it compile on VC++ 2005?memberandrewtruckle28 Feb '08 - 23:32 
Thank you for your reply. I do find that I get depracation warnings related to the use of various buffer functions. If I don't want to switch the depracation warnings off it means I have to resolve these issues.
 
Is it not possible for a "out of the box" VS2005 build to be made available?
 
Thanks.
GeneralProblem (and solution) with menu width on VISTA, when using Unicode characterssussAnonymous27 Dec '07 - 22:32 
I am working with Greek Unicode characters on Vista. I discovered that on Vista, when the "Current language for the non-unicode programs" is set to English, the Unicode menus with Greek characters appear truncated i.e. the words have been cut at the end, with whole words missing some times.
BCMenu predates the release of MS Vista, and digging into the code I discovered that it has a function with the name
 
Win32Type IsShellType()
 
which determines the OS type that is used. As it predates Vista, when is run on Vista it defaults to WINNT3! And this causes all the problems. I have changed the function so when run under MS Vista (or any future versions MS Windows) it returns WINXP as the OS type. This has solved the problem of the truncated menu width.
Now all the tests when run on a 32bit Vista installation. The change most probably will work also for Vist 64-bit.
 
I include the changed code of the function for your reference:
 
Win32Type IsShellType()
{
Win32Type ShellType;
DWORD winVer;
OSVERSIONINFO *osvi;

winVer=GetVersion();
if(winVer<0x80000000){/*NT */

osvi= (OSVERSIONINFO *)malloc(sizeof(OSVERSIONINFO));
if (osvi!=NULL){
memset(osvi,0,sizeof(OSVERSIONINFO));
osvi->dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
GetVersionEx(osvi);
if(osvi->dwMajorVersion==3L)ShellType=WinNT3;
else if(osvi->dwMajorVersion==4L)ShellType=WinNT4;
else if(osvi->dwMajorVersion==5L&&osvi->dwMinorVersion==0L)ShellType=Win2000;
else if(osvi->dwMajorVersion==5L&&osvi->dwMinorVersion==1L)ShellType=WinXP;
else if(osvi->dwMajorVersion==6L&&osvi->dwMinorVersion==0L)ShellType=WinXP; //- Windows Vista
else ShellType=WinXP; //- For future versions of Windows default to WinXP
free(osvi);
}
}
else if (LOBYTE(LOWORD(winVer))<4)
ShellType=Win32s;
else{
ShellType=Win95;
osvi= (OSVERSIONINFO *)malloc(sizeof(OSVERSIONINFO));
if (osvi!=NULL){
memset(osvi,0,sizeof(OSVERSIONINFO));
osvi->dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
GetVersionEx(osvi);
if(osvi->dwMajorVersion==4L&&osvi->dwMinorVersion==10L)ShellType=Win98;
else if(osvi->dwMajorVersion==4L&&osvi->dwMinorVersion==90L)ShellType=WinME;
free(osvi);
}
}

return ShellType;
}
QuestionCan't show the toobar in dialogbased program?membersankking30 Oct '07 - 18:06 
In Demo "BCDialogMenu303".Although the LoadToolbar() function is called , but there wasn't any toolbar show on the dialog. why?
...
m_menu.LoadMenu(IDR_MYTYPE);
m_menu.LoadToolbar(IDR_MAINFRAME);
m_menu.LoadToolbar(IDR_TOOLBAR);
SetMenu(&m_menu);
...

Questionadding records to database table made in acess from the formmemberviks077 Sep '07 - 1:38 
how to store the data in the database using an mfc AppWizard
 
vivek rai
GeneralThanks, what about the highlighted menu items background on Windows Vista and Office 2007 [modified]memberAlexandru Matei1 Apr '07 - 13:17 
Hello,
 
Do you know of an web article describing how somebody can imitate the painting of the highlighted menu items background?
 
1. highlighted menu items in normal applications running on Microsoft Vista (e.g NotePad ) have a nice blue background
 
2. highlighted menu items in Office 2007 (on Windows XP and Windows Vista, doesn't matter, the menu looks the same) have a nice "reflecting light" orange gradient.
 
By reading various articles, I've seen two approaches:
 
- Use themes API functions like DrawThemeBackground(). Is this possible for menus ?
 
Or
 
- Use gradient API functions like GradientFill() with GRADIENT_FILL_RECT_V?
 
In this case, by applying this function twice with different limiting colors for the first half and the second half of the button would produce something aproximating the "reflecting light" gradient we are seeing in Office 2007)
 
I would like to know how the Microsoft programmers implemented these menus.
 
Thanks a lot.
 

 

-- modified at 19:58 Sunday 1st April, 2007
QuestionTheme SupportmemberVikrant for VC++18 Mar '07 - 12:13 
Hi
 
Any idea of how theme support can be added to the menus.
 
menus looks better on vista & worth utilising them.
 
Regards

AnswerRe: Theme Supportmemberandrewtruckle25 May '08 - 12:23 
Any update on this request?
 
Andy
GeneralCannot insert top level menu items (i.e. file, edit, etc)memberHarvinder singh marwaha18 Jan '07 - 2:57 
I'm not able to append/insert top level menu item using the POPUP flag. This behaviour works fine with CMenu, and when i use ....
 
BOOL InsertMenu( UINT nPosition, UINT nFlags, UINT_PTR nIDNewItem = 0, LPCTSTR lpszNewItem = NULL );
 
with nIDNewItem as 0, BCMenu assumes it as a separator, instead of a top level item.
 
Please help me with this.
 
Thanks.

QuestionMenubar Bitmap background colours problemmembersingh_nav8 Nov '06 - 22:33 
Hi
Let me say thanks first for this wonderful help .
 
I am using this code to my SDI application. I am using 3.03 version of bcmenu.
I am facing the problem appling the true color bitmap strip at menubar. My strip background color is RGB(192,192,192) and Even i ve set the function SetBitmapbackground(RGB(192,192,192)). But still it is not showing the transparent background colors of menubar
 
Thx
ND
QuestionHow can I do this?memberSarath.6 Oct '06 - 1:19 
have created an owner drawn menu item and done required drawing in the
DrawItem function. The drawing code works as I expected bu the problems is a
box appearing outside the menu. how can I remove it? please see the following
pictured to see the output.
 
http://static.flickr.com/98/248788817_5aca6ca4f1_o.jpg[^]
 
-Sarath.
"Great hopes make everything great possible" - Benjamin Franklin


Questionwhy the backcolor of the menu is gray?membereagleskycloud23 Aug '06 - 22:38 
Hi,
 
I set xp_draw_3D_bitmaps=FALSE and xp_drawmode=BCMENU_DRAWMODE_ORIGINAL in BCMenu.cpp . then the backcolor of menu is gray.
 
ButI set xp_draw_3D_bitmaps=FALSE and xp_drawmode=BCMENU_DRAWMODE_ORIGINAL in BCMenu.cpp of your MDI example ,the backcolor of menu is white.
 
why the backcolor of menu is different while same set?
 
how to set backcolor of menu to white. could you help me?
 
my application is under vc++6.0 + windows xp
 
Any help will definitely be apprecicated.
AnswerRe: why the backcolor of the menu is gray?membereagleskycloud24 Aug '06 - 22:36 
I've resolve this question.
 
you may change backcolor of menu in BCMenu::DrawItem_Win9xNT2000() or BCMenu::DrawItem_WinXP() function.change the value of m_clrBack variable to change the backcolor of menu.
 
I'm thankful to the author for supporting us a such good class.

GeneralMenuItemTextmemberpjmvn25 Jun '06 - 23:54 
Hi.
I have some problem in VC++ 2005.
When i use this command, the return value is true:
UNIT rt = menu->GetMenuItemCount();
But when i use these functions(here is some examples):
GetMenuText(pos, tmp, MF_BYPOSITION); //error: Unhandled exception at 0x004788f3 in App.exe: 0xC0000005: Access violation reading location 0xcdcdcdcd. At "string=m_MenuList[id]->GetString();" in your code
GetMenuItemID(pos); // value of this function always is "-1"
GetMenuString(pos, tmp, MF_BYPOSITION);//this function always L""

 
Why? I am wrong in use params or the library can not work in VC++ 2005?
 
Please help me.
GeneralRe: MenuItemText [modified]memberGianGian28 Jun '06 - 22:10 
Hi,
i think there are 2 possible problems:
 
- you wrote:
UNIT rt = menu->GetMenuItemCount();
GetMenuText(pos, tmp, MF_BYPOSITION);
GetMenuItemID(pos);
GetMenuString(pos, tmp, MF_BYPOSITION);

 
but the correct code probably is
 
UNIT rt = menu->GetMenuItemCount();
menu->GetMenuText(pos, tmp, MF_BYPOSITION);
menu->GetMenuItemID(pos);
menu->GetMenuString(pos, tmp, MF_BYPOSITION);

 
- probably the 'pos' variable is more bigger than total menu count.
 

Sorry for my english, but i'm italian. Smile | :)
 
bye
GianGian (Marco)
 

-- modified at 4:13 Thursday 29th June, 2006
QuestionHow can i use truecolor bitmap?memberdalgoo9 Mar '06 - 14:26 
I tried using truecolor bitmap. but it is not show image on menu.
Please anwser to me....
 
Go for it!!
AnswerRe: How can i use truecolor bitmap?memberGianGian15 Jun '06 - 4:57 
Hi dalgoo,
for use a truecolor bitmap in the menu is needed to replace all 'ILC_COLORDDB' with 'ILC_COLOR32' in the image list creation.
 
Sorry if my english is not perfect, but i'm Italian. Smile | :)
 
bye, ciao

GeneralRe: How can i use truecolor bitmap?memberwrcgator5 Nov '08 - 2:17 
The trick to true color images is how you create the image list you load. At first it seemed obvious that you would do the following:
 
m_TrayImages.Create (IDB_TRAY_IMAGES, 16, ILC_COLOR24|ILC_MASK, RGB(255,0,255));
 
However, this method loads the bitmap using the half-tone palette which reeks havoc on the colors! The solution is to create the imagelist first then add the bitmap:
 
m_TrayImages.Create (16, 16, ILC_COLOR24|ILC_MASK, 0,0);
	
CBitmap  bmp;
bmp.LoadBitmap(IDB_TRAY_IMAGES);
	
COLORREF rgbTransparentColor = RGB(255,0,255);
	
m_TrayImages.Add(&bmp, rgbTransparentColor);
 
That is it!
GeneralTop of the menus (File, Edit, etc.)membermyst4ever22 Feb '06 - 15:04 
Is there a way to modify the code so that the tops of the menus such as the File, Edit, and Tools menus (for example) to display like the XP sytle?
QuestionHow to set my own disabled imagememberBCPanda24 Jan '06 - 3:11 
Is it possible to set my own disabled image for menu item, like SetDisabledImageList in CToolBarCtrl
AnswerFind myselfmemberBCPanda24 Jan '06 - 3:24 
Just checked version 3.03
Looks like its already has what i need (color disable images)
General32 x 32 bitmapsmemberandrewtruckle9 Jan '06 - 10:12 
I currently use the BCMenu system and it shows my 16 x 16 toolbar images against the relevant menu items.
 
A user has provided me with some 32 x 32 images (256 colours) that he would like me to consider using for my toolbar. I am happy to try but have concerns about what will happen to my menu items.
 
Has anyone done this kind of thing before?
 
Please clarify.
 
Andrew
QuestionBug?memberdanscortyu14 Sep '05 - 3:01 
I could not make a menu item MF_GRAYED
In dialog mode ,
I use BCMENU as main and single menu ,
It run OK,
but ,
I could not make a menu item grayed while CMenu will do.
 
I add code as below in InitDialog function
m_menu.LoadMenu(IDR_MYMENU);
 
m_menu.EnableMenuItem(ID_VLINK_CLOSE,MF_GRAYED);
......
it won't work, why?
 
or I should change it in other function?
 

 

 
Hello,
pleasure to meet you.
AnswerRe: Bug?memberdanscortyu14 Sep '05 - 3:06 
And I test these code in your example,
edit menu ID as your menu ID,
and tried a submenu mode ,
it still can not work! just as nothing happened?
 
Hello,
pleasure to meet you.
GeneralMenu item are disabledmemberNicolas Bernard1 Aug '05 - 23:46 
I've discover that if I remove the 'ON_COMMAND( ..., ... )' for an menu item, this one will appear disabled, and then do not send any message when clicked etc..
 
Is there a way to not getting in charge of adding such command in message map ? I explain myself, I buid dynamicly my menu and so i can't add the ON_COMMAND. I resolve this by using ON_COMMAND_EX_RANGE but I dislike that...
 
I'm pretty new to MFC...
 
Sorry if this question appear dumb... but ...
 
Tx,
QuestionBug in displaying PopupMenu?memberRadioShark16 Jul '05 - 19:47 
I created BCMenu instance with several popup items in main menu and noticed that items with submenu has not the same size as other menu items.
 
See example screenshoot
 
How to fix this problem?

 
Sincerely Yours,
RadioShark
AnswerRe: Bug in displaying PopupMenu?memberAnna-Jayne Metcalfe16 Nov '05 - 0:16 
You need to handle WM_MEASUREITEM etc. in your class.
 
Anna Rose | [Rose]
 
Riverblade Ltd - Software Consultancy Services
 
Anna's Place | Tears and Laughter
 
"Be yourself - not what others think you should be"
- Marcia Graesch
 
"Anna's just a sexy-looking lesbian tart"
- A friend, trying to wind me up. It didn't work.

GeneralHotkeys not working in popups...memberravinderonline20 Jun '05 - 20:26 
HI friends,
 
Its a nice class to make our menus XP Style.I am facing an issue that hotkeys are not working when i use BCMenu as POP Up menu although they are working normally when when i dont use them as context menu..here is sample code
 
BCMenu aMenu;
CPoint pt(X,Y);
ClientToScreen(&pt);
 
switch(itemType)
{
case -1:
{
if(m_tree.CountChildren(root) == 0 && m_nAutoPopulate_Type == 2)
{
aMenu.LoadMenu(IDR_MENU_SITE_ROOT2);
aMenu.GetSubMenu(0)->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON,pt.x+25,pt.y,this);
}
}
Smile | :)
GeneralRe: Hotkeys not working in popups...memberHumberto24 Aug '05 - 14:50 
In the call to TrackPopupMenu replace the this pointer by a pointer to your CMainFrame ( you can get it with AfxGetMainWnd()).
GeneralRe: Hotkeys not working in popups...memberravinderonline28 Aug '05 - 4:51 
hi friend.
 
I got the solution after one month when i posted this thread. Actually in the instruction it was clearly mention to override 3 functions in mainframe.
CMainFrame::OnMeasureItem()
CMainFrame::OnMenuChar()
CMainFrame::OnInitMenuPopup()
 

My problem was that i was using menu in other classes despite mainframe(altough they were part of my project) and i was not overriding these function in my classes. So the solution was to override these function in that particulare class where u want to work with BCMenu.
 
That mean if i used these function in one of my class CSiteTree then need to override these functions again in that particular class.
CSiteTree::OnMeasureItem()
CSiteTree::OnMenuChar()
CSiteTree::OnInitMenuPopup()
 

thanks for replying
ravinder
GeneralInsert a control in a popup menu.memberNegrume4 Nov '04 - 6:14 
Is it possible to insert a control, like an edit box, in a popup menu item?
QuestionHow can use this function SetMenuText?memberKyeongoh,min13 Oct '04 - 20:54 
Now, i am programing my program with BCMenu class.
this program should be made in each language type. and then i have used SetMenuText function for changing menu string.
but i couldn't change upper menu string.
> some code
m_menu.SetMenuText(0,"FILE(&F)"); <-- it didn't change
m_menu.SetMenuText(ID_PHONE_CONNECT,"CONNECT", MF_BYCOMMAND); <-- it changed.
 
How can change upper menu string ?
please help me.. ..
GeneralPopupMEnusussjose.valente9 Sep '04 - 3:49 
I'm having some problems using BCMenu.
 
m_bcMainMenu.CreatePopupMenu();
m_bcMainMenu.SetMenuDrawMode( BCMENU_DRAWMODE_XP );
 
m_bcContextMenu = m_bcMainMenu.AppendODPopupMenu( "Popup menu item" );
m_bcContextMenu->SetMenuDrawMode( BCMENU_DRAWMODE_XP );
 

doing this the string "Popup menu item" doen's appear, it looks like the measure item function doesn't get called.
 
thanks for all your help
Jose Valente
GeneralRe: PopupMEnumemberjose.valente9 Sep '04 - 6:16 
nevermind, it looks like an limitation of the CMenu class.
http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q143209
Generalcompile in vs2003,problem!memberwwwwwwwwwwwww8 Sep '04 - 2:41 
wchar_t * can't change to cstring !!!!Confused | :confused:
GeneralRe: compile in vs2003,problem!memberalex_ger23 May '05 - 12:21 
Hi,
 
I had the same problem, but it was quite simple.
See please: http://www.codeproject.com/buttonctrl/cbuttonst.asp?df=100&forumid=111&select=1114945#xx1114945xx
 
@Brent Corkum:
This may be a "bug" (in VS 2003 .NET)?!?!

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130523.1 | Last Updated 28 Apr 2002
Article Copyright 1999 by Brent Corkum
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid