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

A ToolBarCtrl Based Menubar Control

By , 3 Dec 2001
 

Sample Image - MenuBarXP.jpg

Introduction

This menubar control is based on the CToolBarCtrl class rather than CToolBar, so it never assumes that it has a parent window derived from CFrameWnd. It lacks some features like docking or automatic tooltips, but it can be used with any window whose parent is derived from CWnd. You must of course be using MFC.

Implementation

Between CMenuBar and CToolBarCtrl, I wrote a class named CToolBarXP to process customdraw. If you don't need this feature, just modify the base class as CToolBarCtrl, and remove the following line from the messagemap:

	ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, CToolBarXP::OnCustomDraw)

CToolBarXP includes a LoadToolBar member function to load a toolbar resource. It may be useful to you, even if you don't care about menubars or customdraw.

CMenuXP is used as the menu class to implement ownerdraw. CMenuXP is derived from CMenu so it has all the features of CMenu. If you don't need a ownerdraw menu, just use the CMenu members to construct the menu.

The included sample is simple and far from powerful, but it is a good start I hope.

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

About the Author

Neil Yao
China China
Member
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 | :)

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   
Generalctoolbarxp didn't display textmemberwanglinhai88821 Feb '10 - 20:16 
Hello, I would like to ask, why not use ctoolbarxp display text, there is no other way? Please let me know, thank you!
GeneralSubMenu Bugmemberbenjamin2321 May '08 - 4:39 
The code doesn't seem to catch submenus when using keyboard navigation.
To do that you have to catch WM_MENUSELECT and set a flag when the menu item is a popupmenu so the right works as it is supposed.
GeneralApp suddenly exitsmemberChris982121 Apr '08 - 8:59 
Hi, the application process exits suddenly when I do the following:
 
- open one of the menus, except the leftmost one. E.g., in your example (MenuBarXPApp.exe), click on the "Edit" menu.
 
- while the menu is open. double-click on "Edit" again. The two clicks need to be made quite fast.
 
Now, the applications terminates. The debugger does not show any error message.
 
I'd really appreciate if you could have a look at that problem.
 
Thanks, Chris
GeneralRe: App suddenly exitsmemberhujian_19827 Sep '09 - 19:39 
The reason is that it does not process the double click event, and the second mouse click triggers OnOK() because the id of the item is 1(same as IDOK).
QuestionSEPARATOR bugmemberlihe20057 Sep '06 - 20:16 
MS Standard Menu SEPARATOR not responding to the message that two (WM_LBUTTONDOWN, WM_RBUTTONDOWN). MenuBarXP how to solve with the same standard Like.
Regards ,
GeneralSome improvement (XP themes)memberAlexXF24 Nov '04 - 7:29 
void CToolBarXP::OnCustomDraw( NMHDR * pNotifyStruct, LRESULT* pResult )
{
	NMTBCUSTOMDRAW *pnmcd = (NMTBCUSTOMDRAW *)pNotifyStruct;
	CDC	dc;
	dc.Attach(pnmcd->nmcd.hdc);
 
	switch (pnmcd->nmcd.dwDrawStage)
	{
	case CDDS_PREPAINT:
		*pResult = CDRF_NOTIFYITEMDRAW;
		break;
	case CDDS_ITEMPREPAINT:
		PreDrawItem(&dc, pnmcd->nmcd.rc, pnmcd->nmcd.uItemState);
		*pResult = TBCDRF_NOEDGES  | 0x00400000;
		break;
	case CDDS_ITEMPOSTPAINT:
		break;
	}
	dc.Detach();
}
 
Now it worked with implemented XP Themes by manifest. Smile | :)
GeneralRe: Some improvement (XP themes)memberFrank Overcast22 Jan '06 - 15:40 
Hi Alex,
 
your post is some time ago but I'm curious Laugh | :laugh:
 
I ran in the same problem using this fancy CustomDraw source in a Win32 project.
How did you find out "TBCDRF_NOEDGES | 0x00400000"?
Just try-and-error with TBCDRF_NOBACKGROUND?
 
Cheers,
Frank.

GeneralCatch Click Eventsmembernaumankhan15 Apr '04 - 21:44 
Hi,
 
I have been trying to catch the Left Mouse Click Events on different Menu Items Like Cut, Edit etc in your Demo Project. But HitTest(point) in your CMenuBarXP::OnMenuInput function always returns -ve value which means no option clicked. Please let me know how to catch different Mouse events and to write Event Handlers for Different Mouse events for Menu and Toolbar.
 
Regards
NaumanConfused | :confused:
GeneralRe: Catch Click EventsmemberYao Zhifeng15 Apr '04 - 21:59 
There's no need to capture mouse clicks. whenever a menuitem is clicked, a WM_COMMAND message with menu ID as parameter will be sent to the parent window, so that the parent window can process them. This process is the same as you were using normal menu. The difference is that when write normal menu item handler, the classwizard can generate some code for you, include the handler function and some message mapping macros, however, if you use this class, you have to write these code manually. Check the auto-generated code for how to write macros, it's not hard to use.
GeneralRe: Catch Click Eventsmemberjagan_gadela21 Apr '04 - 1:33 
I am also facing same problem. I though that WM_COMMAND will work for me. But I was not able to catch the evens though. Any alternates? Some thing like using SendMessage Command (I used this, but faced the problem Frown | :(
 

ThanksConfused | :confused: Frown | :(
 
Indians are Lazy Genius
GeneralRe: Catch Click Eventsmemberjagan_gadela21 Apr '04 - 1:58 
I Will Try To Explain what I Did.
 
My Intention is to create the Tool Bar for a button.
 
So I Have taken CButtonST class for my requirements
 
In CButtonST Class declarations I added following code
 
//class declarations
CMenu *pMenuX ;
void AddButtonMenu(CMenu* pMenu);
// In Definations I did like this
 
void CButtonST::AddButtonMenu(CMenu *pMenu)
{

if(pMenuX!=NULL)
{
if(pMenuX->m_hMenu && pMenuX!=NULL)
{
pMenuX->DestroyMenu ();
}
}
pMenuX=NULL;
if(pMenuX==NULL)
{
pMenuX=pMenu;
}
}
And I have Modified OnClcked Method by Adding following code to it
 
if(pMenuX && pMenuX->m_hMenu )
{
CRect rWnd;
GetWindowRect(rWnd);
Invalidate();
CMenu* psub = (CMenu*)pMenuX->GetSubMenu(0);
if (m_csCallbacks.hWnd)
::SendMessage(m_csCallbacks.hWnd, m_csCallbacks.nMessage, (WPARAM)psub, m_csCallbacks.lParam);
//::SendMessage(this->m_hWnd, m_csCallbacks.nMessage, (WPARAM)psub, m_csCallbacks.lParam);
DWORD dwRetValue = psub->TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_NONOTIFY | TPM_RETURNCMD, rWnd.left, rWnd.bottom, this, NULL);
Invalidate();

return TRUE;
}
 

This is How I Have modified the code in CButtonST class
 

And In My Application I tried to work like this
I created a method called CreateToolsButtonMenu
 
CMenu* CXmlparseDlg::CreateToolsButtonMenu()
{

 
//You can unrecomment the next two line to load a normal menu
//pMenu->LoadMenu(IDR_MAINMENU);
//return pMenu;
 

 
CMenuXP *pPopup;
pPopup = new CMenuXP1;
pPopup->CreatePopupMenu();
 
CMenuXP *pButtons = new CMenuXP1;
pButtons->CreatePopupMenu();
pButtons->SetBackColor(RGB(0xf2, 0xf2, 0xf2));
pButtons->SetSelectedBarColor(RGB(0x00, 0xcc, 0xcc));
pButtons->SetMenuStyle(CMenuXP1::STYLE_XP);
 
pButtons->Break();
pButtons->AppendODMenu(0, new CMenuXP1Button(ID_TOOLS_INTERNETEXPLORER, AfxGetApp()->LoadIcon(IDI_EXPLORER)));
pButtons->Break();

 
pPopup->AppendODPopup(0, pButtons, new CMenuXPText(203, "Buttons"));
 
return pPopup;
}
 
and in OnInitDialog method I created button like this
 
m_btnTools.SetFlat(1);
m_btnTools.SetAlign(CButtonST::ST_ALIGN_VERT);
m_btnTools.SetIcon (IDI_TOOLS );
m_btnTools.EnableBalloonTooltip();
m_btnTools.SetTooltipText(_T("Executes the third party applications"));
m_btnTools.AddButtonMenu(CreateToolsButtonMenu());
 

After doing these modifications with yours and other expert Davide Calabro's code(Source : http://www.codeproject.com/buttonctrl/cbuttonst.asp) I was able to see your tool bar wth Davide's Button. But Only Problem I have faced is I am not able to catch the WM_COMMAND messages
 
Regards

 
hfg h hfgh hgfh
GeneralRe: Catch Click EventsmemberYao Zhifeng21 Apr '04 - 4:10 
The WM_COMMAND message will be sent to the window which you designated in TrackPopupMenu function. So, you might try to change that parameter.
GeneralRe: Catch Click Eventsmemberjagan_gadela22 Apr '04 - 2:05 
You Write :

The WM_COMMAND message will be sent to the window which you designated in TrackPopupMenu function. So, you
might try to change that parameter.

 

You mean is that button or main window?
I have created popup menu in CButtonST class means it is designated to button, I assigned same object while creating popup. But it Does not worked.
 
By Assiging Main Window also it does not worked Frown | :(
 
Any help Plz
 

 

GeneralRe: Catch Click EventsmemberYao Zhifeng22 Apr '04 - 23:12 
try this:
psub->TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_NONOTIFY | TPM_RETURNCMD, rWnd.left, rWnd.bottom, this->GetParent(), NULL);

GeneralRe: Catch Click EventsmemberJim Tomasko24 Apr '04 - 22:38 
When I tried the above GetParent() solution, it caused the popup tracking to not work correctly (if you roll over one menu title item, click it to drop the menu, then roll over the next menu title item, it will not drop correctly.)
 
Instead of changing the window handle in TrackPopupMenu, just do the following:
 
If your using the wizards, just add a handler for either the command or commandUI as normal, but insure that you select your view window as the target of the message.
 
If your hand editing do the following in whatever window you childed the menu to...
 
1. Add handlers for update UI and WM_COMMAND messages like this...
afx_msg void OnUpdateYOUR_MENU_ITEM(CCmdUI *pCmdUI);
afx_msg void OnYOUR_MENU_ITEM();
 
2. In the message map of the view class, add maps to the above functions like this...
 
ON_UPDATE_COMMAND_UI(ID_YOUR_MENU_ITEM, OnUpdateYOUR_MENU_ITEM)
ON_COMMAND(ID_YOUR_MENU_ITEM, OnYOUR_MENU_ITEM)
 
Lastly... I'd like to say I think you've done a bang-up job with this. It's saved me a ton of work that I would have had to do on my own, and it works great!!! I salute you.

Questionpossible to use this on SDI???memberHirosh16 Feb '03 - 20:57 
possible to use this on SDI???
 
Hirosh
www.hirosh.tk
GeneralPretty cool, only one thing thoughmemberAnonymous11 May '02 - 0:50 
The keyboard navigation (Right/Left keys) won't work when the current focus is on a subitem in the menu that is a popup (When you press Right/Left it won't pop the submenu, it'll switch to the next menu).
I faced the same problem when trying to implement this in my own app, here's how I got around it: I tapped VK_DOWN and VK_UP and basically tracked which subitem the user is focusing on, then when the user presses VK_RIGHT or VK_LEFT, I either let the submenu process the message or process it myself (According to what subitem the user is on). You'll also need to tap on WM_MOUSEMOVE btw... Sucks, but it works Smile | :)
 
Nice work Smile | :)
Questionhow to change the color of the toolbar?memberAnonymous1 May '02 - 19:40 
and the color of the menu?
GeneralI have a problem!!!memberCSZX3 Apr '02 - 0:48 
My problem is that, when I try to build this project in Debug version
I always got an error message:
 
C:\USERS\csz\c++\MenuBarXP\MenuBarXPApp.rc(20) : fatal error RC4214: Codepage not valid: ignored
 
What is the problem?
 
Circumstances: WinNT, VC6.0:
 
Confused | :confused:
 
CSZX
GeneralDoesn't work with dropdown arrow.memberDuc Truong14 Jan '02 - 14:23 
Has anybody tried this CToolBarCtrl based control with the TBSTYLE_DROPDOWN style? The edge of the arrow still shows up when a button with dropdown arrow has mouse over it.
 
Is it a MS bug or I'm not handling the TBSTYLE_DROPDOWN button style properly?
 
Thanks for the contribution, Yao Zhifeng!
 

 
In programming you can do anything (by Paul DiLascia)
GeneralChanging background color of MenumemberRitesh2321 Dec '01 - 22:36 
I am beginer in Vc++ and MFC for my assignement I want to change only backgriounds color of menu item in internet explorer.
Is anybody there help me with that.
Frown | :(
GeneralGood jobmemberCool_worm19 Dec '01 - 1:37 
Big Grin | :-D
GeneralMenu icon lost itself when mousemove on the popup menu itemsmemberGolden Lee10 Dec '01 - 15:46 
Hi, Mr. Yao Zhifeng:
 
Thank you for your cool XP-style MenuBar class. In addition to for menu icon to lost itself when mousemoving the popup menu
 
items with "a bit of speed", it generally works great in my dialog-based app. What precautions could I take to avoid this fly
 
in butter?
In reply to the question "What about message handle", your answer is simple and easy to follow. This seems to make the menu
 
item's ON_IDM_XXX:COMMAND message to be treated easy, no response to ON_IDM_XXX:UPDATE_COMMANDD_UI messages. I know that any
 
OnUpdate handlers which included in the dialog's message map will never be called in a dialog-based application. But by
 
handling the dialog's WM_KICKIDLE message, and mimicking MFC's routing of its UPDATE_UI messages, you can implement this with
 
a little work (John Wismar: http://www.codeguru.com/dialog/OnUpdate.shtml). I follow this article in a step-by-step way to
 
try to toggle the check mark initially put in front of a menu item using the statement
pPopup->AppendODMenu(MF_CHECKED, new CMenuXPText(IDM_SETTINGS_FTP, "&FTP Transfer")); in OnUpdateFTPTRansfer(CCmdUI* pCmdUI)
message handler, but nothing was happened. Any suggestions as well as some tips will be highly appreprited.
Thank you for your nice code again!
 
Golden Lee
 
Golden Lee
GeneralGetParentmemberorcun colak6 Dec '01 - 17:44 
According to my observation after adding the menubar to CReBarCtrl the parent of menubar gets set to CReBarCtrl although in the beginning it was our main window. The messages sent from menubar control are sent using GetParent()->SendMessage so the messages are going to CReBarCtrl .
I think it is better to send the messages to main window using
AfxGetMainWnd()->SendMessage. For example if we want to enable/disable a menu item when menu pops up ,probably it is better to process the message in the main window.
 
Besides this minor thing the author has done a god job.

 
Orcun Colak

GeneralRe: GetParentmemberYao Zhifeng7 Dec '01 - 4:13 
I have changed all the GetParent call with GetOwner. So just call SetOwner to register the owner window. I don't want AfxGetMainWnd appear in my code because the main purpose of writting these code is to keep it lite and less dependency.
 
Thank you for your suggestion

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

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130523.1 | Last Updated 4 Dec 2001
Article Copyright 2001 by Neil Yao
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid