Introduction
Microsoft introduced a new feature some Office versions ago: Popup menus you can tear off and use as toolbars. This is a good way for the user to put important functions directly on the application workspace without opening a menu each time.
Trying to implement this feature caused a lot of problems. The easiest thing was to draw the menu so it looks like you can tear it off. The next thing was how to get the mouse movements and button pressed, which caused me to stop working on this for a long time. In the November 2003 issue of the MSDN magazine, Paul DiLascia wrote some code to display menu tooltips. With this code, it was quite easy to get it working.
Behind the Scenes
The new class CMenuTearOffManager
has all the functions you need for tear-off menus. It basically maps popup menus to toolbars and handles the GUI part. Using Paul DiLascia CSubclassWnd
class CMenuTearOffManager
reacts on every new popup menu and checks (and modifies) it in case it has a tear-off item. Then the "caption" is calculated and painted. Let's see how it works inside: First, whenever a new popup menu is opened (WM_INITMENUPOPUP
), it goes through all items and compares them to the internal map that assigns menu items to toolbars. In case this item is found, it is converted to an ownerdrawn
item. For that item, WM_MEASUREITEM
calculates the height for the "caption" and WM_DRAWITEM
paints the caption. And here's the tricky part: during painting, a new window is created that lays above the menu item, so mouse moves an be trapped; each time you select a different menu item, the window gets invisible. The new window is not active (which would cause the menu to close), so mouse moves are captured by WM_NCHITTEST
. Moving the mouse and pressing the left mouse button closes the window and forwards the message to the toolbar control - that's it!
Using the Code
First, add the CMenuTearOffManager
class to the CMainFrame
. In your CMainFrame::OnCreate()
, add all tear-off toolbars using code like this:
if (!m_wndToolBarTearOff1.CreateEx(this, TBSTYLE_FLAT, WS_CHILD
|WS_VISIBLE| CBRS_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBarTearOff1.LoadToolBar(IDR_TEAROFF1))
{
TRACE0("Unable to create toolbar 1\n");
return -1;
}
m_wndToolBarTearOff1.EnableDocking(CBRS_ALIGN_ANY);
ShowControlBar(&m_wndToolBarTearOff1, FALSE, FALSE);
(The last line of code causes the toolbar to be initially invisible.)
Then, insert a new menu item on top of each popup you'd like to act as a tear-off menu (here: ID_TEAROFFDEMO_TEAROFF2
). Also insert new toolbars that are displayed for the popup menus. There's no need to have the same commands on the toolbar.
After creating all toolbars, use these lines to install the class and connect it to menu items:
m_menuTOManager.Install(this, this);
m_menuTOManager.AddTearOff(ID_TEAROFFDEMO_TEAROFF1, &m_wndToolBarTearOff1);
m_menuTOManager.AddTearOff(ID_TEAROFFDEMO_TEAROFF2, &m_wndToolBarTearOff2);
...
This connects the "virtual
" menu item ID_TEAROFFDEMO_TEAROFF2
to the toolbar m_wndToolBarTearOff2
. All the rest is done automatically.
Please see the sample how to use it. All comments are in English, only the resources are in German.
Limitations
This class has a few differences to the "original" implementation you know from e.g. Microsoft Office and some other limitations:
- Different drawing of the tear-off caption
- Menu closes immediately after tearing the toolbar away
- Office products allow to doc the popup again during dragging
- Not (yet) possible for context menus
- Not tested for ownerdrawn menus, but it should work
Credits
Paul DiLascia for his subclass class and the menu tip manager, which helped a lot in developing this class!
History
- 30.11.2003: Initial release
License
Feel free to use this class in any of your projects or modify it! Please keep my credits in the source.
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.