A Flat Popup Menu for Controls
CFlatPopupMenu
One thing has always bothered me about web-style controls that pop up menus, and that's the way that the menus don't look as if they are owned by the control. The default Windows menus with their 3D look always look like they belong to the browser and not to the control, hence I wrote this popup menu replacement that looks a lot better when owned by a control.

The class doesn't actually use any MFC so you're OK to go ahead and use it in ATL projects designed for web-based distribution. It also supports keyboard shortcuts and the bitmaps seen in recent Microsoft Office applications. All the colors are independently configurable at run-time so that you can make it fit in with your control's look and feel.
How to use it
- I use the STL implementations of string and vector so you'll have to ensure that you add #include <string> and #include <vector> to your stdafx.h file.
- Declare as many instances of CFlatPopupMenu as you require. You will need one for each menu and submenu.
- Call any SetXXX functions that you need in order to change the font, colors etc.
- Call Create() once for each menu and submenu object.
- Call AppendItem() and AppendPopup() as many times as necessary for your menu.
- Call Track() to display the menu.
OK, here's a breakdown of the class members you should know about as they stand today.
void SetFont(LPCTSTR pszFont)
Sets the font used in the menus. The default font is "MS Sans Serif"
void SetFontSize(const int size)
Sets the size of the font (in points) used in the menus. The default font size is 8 points. At present you should ensure that the font size does not exceed 17 pixels.
void SetPopupDelay(const int delay)
Sets the delay, in milliseconds, between a mouse entering a menu item that has a submenu attached, and that submenu being displayed. The user can always bypass the delay by clicking with a mouse button, just like the standard menus. The default value is 400ms.
void SetColor(const menuColor id,const COLORREF cr)
Sets one of the colors used in displaying the menu. The cr parameter specifies the color and the id parameter specifies one from the menuColor enumeration as listed below.
| colorBorder | Border color. Also used as the separator color |
| colorBackground | Background area color |
| colorText | Unselected menu item text color |
| colorGrayedText | Grayed (disabled) menu item text color |
| colorHighlightText | Highlighted (selected) menu item text color |
| colorHighlight | Highlighted item bar (background) color |
| colorLightShadow | Used to draw top and left 3D effect around selected icons |
| colorDarkShadow | Used to draw bottom and right 3D effect around selected icons |
| colorIconTransparent | Background color of icons that you can see through. |
bool Create(HINSTANCE hInstance,const UINT bitmap_id=(UINT)-1)
Called to create, but not display the menu. You must call this after calling the formatting functions and before tracking the menu. MFC users will get the hInstance parameter by calling AfxGetInstanceHandle(), ATL users will get it by accessing _Module.m_hInst. The bitmap_id parameter specifies the resource identifier of the bitmap that the menu will load its icons from, the default value of -1 means that the menu does not contain icons. The bitmap consists of a strip of 16x15 icons (as used for toolbar buttons) indexed from the left starting at zero, as illustrated by the snapshot below which was taken from the bitmap editor in Developer Studio. The bright pink background color is used as the transparent color in the menu.
![]()
The function returns true or false to indicate success or failure.
bool AppendItem(const DWORD dwFlags,LPCTSTR pszName,const UINT itemid,const int icon=-1)
Call this function to add a new item to the end of the menu. dwFlags contains any of the following flags combined with a bitwise OR.
| itemSeparator | Item is a separator. Should not be combined with any other flags |
| itemNotSelectable | Item is not selectable by the user. |
| itemGrayed | Item is displayed in grayed text. Usually combined with itemNotSelectable. |
| itemBold | Item is displayed using a bold font. Good for non-selectable titles. |
pszName contains the text to display as the menu item, separators can pass NULL for this parameter. To include a keyboard shortcut for an item, prefix the shortcut character with an ampersand (&). itemid holds a non-zero identifier that is returned when the item is selected by the user. Non-selectable items and separators can pass zero for this parameter. icon holds the zero-based index of the icon image in the bitmap strip passed to the Create() function or -1 if there is no icon associated with this item.
The function returns true or false to indicate success or failure.
bool AppendPopup(const DWORD dwFlags,LPCTSTR pszName,CFlatPopupMenu& popup,const int icon=-1)
Call this function to add a new popup submenu to the end of a menu. dwFlags, pszName and icon are the same as in AppendItem() but you should not set the separator flag. popup is the actual submenu object that you want to associate with this menu item. This function does not take ownership of popup which means that if you allocated it with new then you should delete it.
The function returns true or false to indicate success or failure.
UINT Track(int x,int y,HWND hWnd,const bool bModal,const bool bPopup=false)
Call this function to display the menu and track the user selection. x and y define the position of the top-left corner of the menu in screen co-ordinates. if bModal is true then hWnd is NULL, otherwise it is the window handle to post the WM_COMMAND message of the selected item to. bPopup is an internal parameter and should never be set by the user, always use the default value of false.
If bModal is true then function returns the item ID of the selected menu item, or zero if no item was selected. If bModal is false then the function returns zero.
An Example
This little code snippet demonstrates how simple it is to create and track a menu:
CFlatPopupMenu menu; CPoint p; int id; // set some of the colors menu.SetColor(CFlatPopupMenu::colorBorder,m_crText); menu.SetColor(CFlatPopupMenu::colorText,m_crText); menu.SetColor(CFlatPopupMenu::colorBackground,m_crBack); // create it menu.Create(AfxGetInstanceHandle(),IDB_FILE); // add some items menu.AppendItem(0,"&New...",1,0); menu.AppendItem(0,"&Open...",2,1); menu.AppendItem(0,"Close",3); menu.AppendItem(CFlatPopupMenu::itemSeparator,NULL,0); menu.AppendItem(0,"&Save",4,2); menu.AppendItem(0,"Save &As...",5); menu.AppendItem(0,"Save A&ll",6,3); menu.AppendItem(CFlatPopupMenu::itemSeparator,NULL,0); menu.AppendItem(0,"Page Set&up",7); menu.AppendItem(0,"&Print...",8,4); // track it p.x=m_rcFile.left; p.y=m_rcFile.bottom-1; ClientToScreen(&p); id=menu.Track(p.x,p.y,NULL,true); if(id>0) // do something with 'id' else // user cancelled the menu
Downloads
Download demo project - 48 KbDownload source - 10 Kb

Comments
problem in Track(...)
Posted by sbarker on 01/04/2006 02:54pmIn the original, when destroying the menu, occasionally it would get a message and never dispatch it. (In the case where GetMessage returned true, but m_hWnd had been destroyed). Pretty tiny problem, but for the desired functionality, the message loop should be changed to: // go into a modal loop while(IsWindow(m_hWnd)) { if(GetMessage(&msg,NULL,0,0)==TRUE) { TranslateMessage(&msg); DispatchMessage(&msg); } else { break; } }ReplySome fixing for runtime menu usage
Posted by BOIL on 12/29/2005 07:58amAnyway, big thanks to the author There are a couple of problems when it is taken to dropdown button menu: 1) menu self closing during navigation 2) self hunging at GetMessage loop For detailed information contact me (for free, of course, :-) ) and I'll send changed source or publish it (FlatPopupMenu.cpp, FlatPopupMenu.h)
ReplyWhere can I contact Andy Brown?
Posted by Legacy on 08/31/2002 12:00amOriginally posted by: BC
Apparently, Andy Brown doesnt use this email address anymore and I'd really like to contact him. Can anybody help?
ReplyIs there has the menu supporting thange font on it
Posted by Legacy on 06/22/2002 12:00amOriginally posted by: okush
I seek everywhere to fin menu which supporting change
Replyfont but i cannot find it anywhere Please somebody tell
me where to find it Thank you
regarding menu
Posted by Legacy on 04/26/2002 12:00amOriginally posted by: mohan
Hi Andy,
ReplyYour sample was so Cool, solved my problem.
I have got a question(could be simple to U,think so)
,
got several classes(actually Dialog box as CFormView as base class), need to display them when mouse is clicked.
I'm wondering 'coz dialog class derived from CFormView doesn't have 'doModal' as like the classes derived from CDialog.
Hope im'not troubling you.
regards,
mohan
Fixing the lose focus on the parent window problem
Posted by Legacy on 01/18/2002 12:00amOriginally posted by: Mike Jackson
ReplyFocus Problem
Posted by Legacy on 08/22/2001 12:00amOriginally posted by: samtree
nice~!!
but when i push the menu, i don't want to kill focus of parent window.
in other words, i don't want that menu get focus.
good bye~
Reply
runtime menus
Posted by Legacy on 08/21/2001 12:00amOriginally posted by: kiran
can u help in handleing runtime menus. i was able to generate menus during runtime but i donot know how to handle
them.
my requirement is i have a candidate table he has a status as Accepted or Rejected. on right click i am fetching these status from the database table called status and creating the popup menu for it. but i am not able to handle them.
if u have got the solution pls send me to my mail
akiranbabu@yahoo.com
thanks in advance,
regards,
Replykiran.
nice, but it crashes...
Posted by Legacy on 07/12/2001 12:00amOriginally posted by: ledz
very nice work...
but, and I have to say but... it's crashing, sometimes...
here's an example, i used this on a separate dll of a modal dialog, and... the first time i load up the dll, and popup the menu, all very nice... i can do everything i want... i close the modal dialog (and the dll), and reopen it again... and once again, i popup the menu... surprise of surprises... my applications terminates... puff!! gone... got an explanation for this?
any way, good work (;
[[]]
ReplyAnother resource leak
Posted by Legacy on 05/14/2001 12:00amOriginally posted by: keva
ReplyLoading, Please Wait ...