Click here to Skip to main content
15,888,286 members
Articles / Desktop Programming / MFC

A Powerful Ownerdraw Menu

Rate me:
Please Sign up or sign in to vote.
4.92/5 (33 votes)
23 Oct 20012 min read 731.4K   9K   111   105
An XP-style ownerdrawn menu with support for background images and icon shadow

Sample Image - MenuXP.jpg Sample Image - MenuXP2.jpg Sample Image - MenuXP3.jpg

A Fully Featured Owner-draw Menu Class

CMenuXP is a class derived from CMenu using ownerdraw technology. I named it MenuXP because I expected it to be like the menus found in Office XP and Windows XP, but I failed to accomplish it. The main difficulty that I had was converting the 3D border of the menu into a flat one, but I hope it is still useful to you.

I constructed the class from the Scribble sample application and some of the drawing code is copied from the CCoolMenuManager class. Additionally, I have also used a class named CBCGKeyHelper from BCGControlBar to show the accelerator key text.

Features

  1. Menu with icons, like in Office 97
  2. A sidebar in any level of the popup menu
  3. Supports button-style menu items, such as is found in some drawing toolbars of the Microsoft Office suite
  4. All colors, fonts and sizes can be customized

Introduction

An item in the menu is represented by the CMenuXPItem class. Some further classes are derived from it which provide convenient uses:

  • CMenuXPText presents a normal menu item with text and an optional icon
  • CMenuXPSeparator presents a separator
  • CMenuXPSideBar presents a sidebar on the left of a popup menu
  • CMenuXPButton presents a button only menu item, which contains the icon only

Knowing this will help you to understand the code.

How to Use as a Popup Menu

  1. Construct a CMenuXP instance
  2. Call CreatePopupMenu
  3. Add a sidebar using AddSideBar if needed
  4. Add some menu items using AppendODMenu
  5. If there is second level popup menu, construct it using steps 1 to 4 and add it to the current menu using AppendODPopup
  6. Call TrackPopupMenu as normal

The example code would be like this:

C++
void CMenuXPAppView::OnContextMenu(CWnd* pWnd, CPoint point)
{
	CMenuXP	*pMenu = new CMenuXP;
	pMenu->CreatePopupMenu();

	pMenu->AddSideBar(new CMenuXPSideBar(24, "MenuXP"));
	pMenu->AppendODMenu(0, new CMenuXPText(10, "First Item",
                               AfxGetApp()->LoadIcon(IDI_ICON1)));
	pMenu->AppendODMenu(0, new CMenuXPText(11, "Second Item",
                               AfxGetApp()->LoadIcon(IDI_ICON2)));
	pMenu->AppendODMenu(0, new CMenuXPText(12, "Another Item",
                               AfxGetApp()->LoadIcon(IDI_ICON3)));
	pMenu->AppendODMenu(0, new CMenuXPText(13, "No Icon"));

	CMenuXP *pPopup = new CMenuXP;
	pPopup->CreatePopupMenu();
	pPopup->AppendODMenu(0, new CMenuXPButton(21,
                                AfxGetApp()->LoadIcon(IDI_ICON4)));
	pPopup->AppendODMenu(0, new CMenuXPButton(22,
                                AfxGetApp()->LoadIcon(IDI_ICON5)));
	pPopup->AppendODMenu(0, new CMenuXPButton(23,
                                AfxGetApp()->LoadIcon(IDI_ICON6)));
	pPopup->Break();
	pPopup->AppendODMenu(0, new CMenuXPButton(24,
                                AfxGetApp()->LoadIcon(IDI_ICON7)));
	pPopup->AppendODMenu(0, new CMenuXPButton(25,
                                AfxGetApp()->LoadIcon(IDI_ICON8)));
	pPopup->AppendODMenu(0, new CMenuXPButton(26,
                                AfxGetApp()->LoadIcon(IDI_ICON9)));
	pPopup->Break();
	pPopup->AppendODMenu(0, new CMenuXPButton(27,
                                AfxGetApp()->LoadIcon(IDI_ICON10)));
	pPopup->AppendODMenu(0, new CMenuXPButton(28,
                                AfxGetApp()->LoadIcon(IDI_ICON11)));
	pPopup->AppendODMenu(0, new CMenuXPButton(29,
                                AfxGetApp()->LoadIcon(IDI_ICON12)));

	pMenu->AppendODPopup(0, pPopup, new CMenuXPText(0, "Popup",
                                AfxGetApp()->LoadIcon(IDI_ICON1)));

	pMenu->TrackPopupMenu(TPM_LEFTBUTTON, point.x, point.y, this);

	delete pMenu;
}

The object constructed on the heap will be destroyed automatically, except for the toplevel popup menu which will need to be destroyed manually.

Remember to add the code below in the WM_MEASUREITEM handler of your parent window:

C++
void CMenuXPAppView::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
	// TODO: Add your message handler code here and/or call default
	HMENU hMenu = AfxGetThreadState()->m_hTrackingMenu;
	CMenu	*pMenu = CMenu::FromHandle(hMenu);
	pMenu->MeasureItem(lpMeasureItemStruct);

	CView::OnMeasureItem(nIDCtl, lpMeasureItemStruct);
}

That's all, I hope this is useful to you. Bug reports and improvements are welcome.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below.

A list of licenses authors might use can be found here.


Written By
China China
I'm a chinese programer living in Shanghai, currently working for a software company whose main business is to deliver computer based testing. Software simulation for computer based testing and certifications is my main responsibility in this company. Execpt for software development, I like out-door activities and photography. I am willing to make friends in China and all over the world, so contact me if you have anything in common with meSmile | :)

Comments and Discussions

 
GeneralRe: Anyone get this working with a system tray application Pin
20-Dec-01 6:53
suss20-Dec-01 6:53 
GeneralRe: Anyone get this working with a system tray application Pin
SAHorowitz20-Dec-01 13:10
SAHorowitz20-Dec-01 13:10 
QuestionHow can I ignore replacing WM_MEASUREITEM message Pin
Bui Huy Kien14-Dec-01 16:17
Bui Huy Kien14-Dec-01 16:17 
AnswerRe: How can I ignore replacing WM_MEASUREITEM message Pin
Neil Yao14-Dec-01 17:26
Neil Yao14-Dec-01 17:26 
GeneralAdding the XP Menu as a submenu to a main program menu Pin
13-Dec-01 12:16
suss13-Dec-01 12:16 
GeneralDont' work on Win95 Pin
Franz Klein13-Dec-01 2:34
Franz Klein13-Dec-01 2:34 
GeneralMinor bug :) Pin
12-Dec-01 13:11
suss12-Dec-01 13:11 
GeneralRe: Minor bug :) Pin
Neil Yao12-Dec-01 15:14
Neil Yao12-Dec-01 15:14 
GeneralMember CMenuXP does not work Pin
12-Dec-01 12:43
suss12-Dec-01 12:43 
Generalnice, but "break" Pin
10-Dec-01 16:36
suss10-Dec-01 16:36 
GeneralRe: nice, but "break" Pin
Neil Yao10-Dec-01 17:52
Neil Yao10-Dec-01 17:52 
GeneralMenu icon lost itself when mousemove on the popup menu items Pin
10-Dec-01 15:42
suss10-Dec-01 15:42 
GeneralRe: Menu icon lost itself when mousemove on the popup menu items Pin
Neil Yao10-Dec-01 18:07
Neil Yao10-Dec-01 18:07 
GeneralUpdate Pin
Bill Leibold9-Dec-01 6:58
Bill Leibold9-Dec-01 6:58 
GeneralWhy you failed - are you aware that... Pin
Juan Miguel Venturello6-Dec-01 17:56
Juan Miguel Venturello6-Dec-01 17:56 
QuestionWhat about message handle? Pin
5-Dec-01 20:55
suss5-Dec-01 20:55 
AnswerRe: What about message handle? Pin
Neil Yao6-Dec-01 0:32
Neil Yao6-Dec-01 0:32 
General你好,我们是同胞 Pin
attckboy8-Nov-01 19:17
attckboy8-Nov-01 19:17 
GeneralCorrupt shell-menus after XP-menu call Pin
26-Oct-01 5:11
suss26-Oct-01 5:11 
GeneralThanks!!! Pin
Youknowme25-Oct-01 15:07
Youknowme25-Oct-01 15:07 
GeneralGetting the menu shortcut keys to work in the demo Pin
25-Oct-01 3:48
suss25-Oct-01 3:48 
GeneralText in DrawSideBar +Fix Pin
Brian V Shifrin25-Oct-01 0:49
Brian V Shifrin25-Oct-01 0:49 
GeneralRe: Text in DrawSideBar +Fix Pin
25-Oct-01 2:15
suss25-Oct-01 2:15 
Generalsecond mousemove to popup Pin
Dieter Hammer24-Oct-01 23:06
Dieter Hammer24-Oct-01 23:06 
GeneralProblem on WinNT sp5 Pin
24-Oct-01 6:04
suss24-Oct-01 6:04 

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

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.