Download Source Code and Example 200KB
This article is based on Visual Studio/Office 97 style Flat
Toolbar and Dockable Menu bar from Tony
Hoyle .
Like many people, I wanted to give to my applications the fancy look from Visual
Studio/Office 97. As a frequent visitor of CodeGuru, I saw and tried the miscellanous
sources related to that subject.
What I liked in Tony’s code is its shortness, but for myself his code have two major
problems:
- Sub-menus couldn’t be shown
- All the menu navigation has to be simulated.
Basically, what’s happening in Tony’s code:
In your FrameWnd you call the CNGenericMenu::SetMenu function to load the menu. Then,
when the user click/Shortcut a menu, a Notify Reflect on the CNGenericMenu::OnShowMenu is
triggered, this function then call the CNGenericMenu::ShowDropDown.
This last function, extract a sub-menu from the menu title, and sends it to
CNGenericPopup::ShowMenu. This function in turn, is responsible for creating a window in
which the menu will be drawn/emulated.
In fact, what must be done there is to change the place where the menu has to be
painted, and if possible to use a standard behaviour.
For our help, the CMenu class has a TrackPopupMenu function. This function is used
normally to show a contextual popup-menu when the user is using the Right click on any
object. For our help, there are no differences between the normal and contextual
menus. So what has only to be done there, is to call it with the hMenu given by
CNGenericMenu::ShowDropDown.
After all this, the ShowMenu function becomes:
BOOL CNGenericPopup::ShowMenu(BOOL bFromKey, int x, int y, CWnd* pParent, HMENU hMenu){ ASSERT(hMenu); HideMenu(); m_pMenu->m_hMenu=hMenu; m_pParent=pParent; if ((FALSE == m_bIsAttached) && (TRUE == m_cSubMenu.Attach (m_pMenu->m_hMenu))) { m_cSubMenu.TrackPopupMenu (TPM_LEFTALIGN , x , y , m_pParent , NULL); m_pParent->SendMessage(WM_ENTERMENULOOP,FALSE); m_bIsAttached = TRUE; } if(bFromKey) { m_pParent->SendMessage (WM_MENUSELECT , 0 , (LPARAM)hMenu); } return TRUE; }Then we arrived on an other problem: when the user, goes from one menu to an other, we
have to close the opened menu before creating the new one. To do it, the CMenu is no help
for us. We have to use directly the different menu events.If you use the Spy++ from the Developper Studio, you’ll see that the WM_EXITMENULOOP
event is sent to close the currently opened menu; so that’s exactly what we are going to
do. The only thing that we must take care on is to Detach the hMenu, prior to sending the
WM_EXITMENULOOP event.So the HideMenu function becomes:
BOOL CNGenericPopup::HideMenu() { if (m_bIsAttached == TRUE) { m_cSubMenu.Detach (); m_pParent->SendMessage(WM_EXITMENULOOP,(WPARAM)FALSE,0); m_bIsAttached = FALSE; } return TRUE; }
Finally, the last problem that subsists is when we click on the header of a menu to
show the menu, then click on it again to close it. To have the correct behaviour, we must
change slitly the CNGenericMenu::ShowDropDown function, and in it to force the close of
the submenu by calling explicitely the HideMenu function. On the same occasion, we can
suppress the ON_DISMISS event which now isn't used any more.
By doing things that way, we are now able to use all the different classes that you
can find on this site to enhance the display of your menus and sub-menus, and have a good
lightweight framework to base your work on.
Last updated: 03 June 1998