Download demo project - 58 KbDownload source files - 11 Kb
Introduction
I needed a toolbar with drop down arrows so that I could place some pop-up
menus on them. Initially I tried handling the notification messages from within
the parent window. This became a huge mess and was just plain ugly looking.
So I decided instead to create my own custom toolbar control. The process
is quite simple so I'll get right to the code:
How it works
1. We needed to retrieve the notification messages from the parent window.
Now, we don't just want to go and reflect all of the notification messages since
we don't want to have to handle all of them. So we create a contained window,
with which we can selectively chose which notification messages were going to
handle.
CContainedWindow m_wndParent;
CToolBarCtrlExImpl() :
m_wndParent(this, 1),
m_pDropDownButtons(NULL),
m_bImagesVisible(false),
m_bAnimate(false),
m_clrMask(RGB(192, 192, 192))
{
}
LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& )
{
CWindow wndParent = GetParent();
CWindow wndTopLevelParent = wndParent.GetTopLevelParent();
m_wndParent.SubclassWindow(wndTopLevelParent);
}
2. We've now got a copy of the parent window and are receiving all of its messages.
Next we need to define in the message map which messages were going to process.
BEGIN_MSG_MAP(CToolBarCtrlExImpl)
ALT_MSG_MAP(1)
NOTIFY_CODE_HANDLER(TBN_DROPDOWN, OnParentDropDown)
NOTIFY_CODE_HANDLER(TBN_HOTITEMCHANGE, OnParentHotItemChange)
END_MSG_MAP()
Notice that were using ALT_MSG_MAP(1)
. ATL supports multiple
message maps, so all messages that belong to the parent window are now been
pumped through here. By the way, the parent window still receives all these
messages, we're just taking a peek at them and using the ones we need.
The following code is the current message handlers in the toolbar class:
LRESULT OnParentDropDown(int , LPNMHDR pnmh, BOOL& bHandled)
{
LPNMTOOLBAR lpnmtb = (LPNMTOOLBAR)pnmh;
if (pnmh->hwndFrom != m_hWnd)
{
bHandled = FALSE;
return TBDDRET_NODEFAULT;
}
_DropDownButton* pb = FindDropDownButton(lpnmtb->iItem);
RECT rc;
GetRect(pb->uIdButton, &rc);
ClientToScreen(&rc);
if (pb && pb->uIdMenu)
if (DoDropDownMenu(pb->uIdMenu, &rc)) <- See History for comments
return TBDDRET_DEFAULT;
return TBDDRET_NODEFAULT;
}
LRESULT OnParentHotItemChange(int , LPNMHDR pnmh, BOOL& bHandled)
{
LPNMTBHOTITEM lpnmhi = (LPNMTBHOTITEM)pnmh;
if (pnmh->hwndFrom != m_hWnd)
{
bHandled = FALSE;
return 0;
}
DWORD dwProcessID;
::GetWindowThreadProcessId(::GetActiveWindow(), &dwProcessID);
if ((!m_wndParent.IsWindowEnabled() || ::GetCurrentProcessId() != dwProcessID))
return 1;
else
{
bHandled = FALSE;
return 0;
}
}
Updates
I just finished adding bitmaps to the menu, so that all menu items that would
usually display a bitmap, will.
How to use
In MainFrm.h declare a CToolBarCtrlEx and in the OnCreate handler initialize
it like the below example.
class CMainFrame : ...
{
CToolBarCtrlEx m_wndToolBar;
LRESULT OnCreate(UINT , WPARAM , LPARAM , BOOL& )
{
HWND hWndToolBar = m_wndToolBar.Create(m_hWnd, rcDefault, NULL, ATL_SIMPLE_TOOLBAR_PANE_STYLE);
m_wndToolBar.LoadToolBar(IDR_MAINFRAME);
m_wndToolBar.LoadMenuImages(IDR_MAINFRAME);
m_wndToolBar.AddDropDownButton(ID_FILE_NEW, IDR_MAINFRAME);
m_wndToolBar.AddDropDownButton(ID_FILE_OPEN, IDR_POPUP_OPEN);
m_wndToolBar.AddDropDownButton(ID_EDIT_PASTE, IDR_POPUP_PASTE);
}
};
Thanks to Paul DiLascia for the code to add drop-down menus to toolbar buttons.
(MSJ - 1997)
That's it!.
History
Version 1.1
- Revised the drop down method and made it a virtual function so that it can
be overridden for custom handling.
- Added bitmaps to the menu items.
Version 1.0
- Added drop down menus to the drop-down buttons.
Ben was born in New Zealand and grew up in Mexico; however, he has lived in Canada for most of his adult life. He has traveled to a few places in Canada so far: British Columbia, Saskatchewan, Manitoba, Ontario and Nova Scotia, but has only ever lived in Alberta —
all over Alberta. From Lethbridge to Calgary to Fort McMurray: he has seen most of what the province has to offer. He has also left the comfort of his—at the time—home country and gone abroad. In recent history he has been in China, New Zealand, the US, Central America and back to Canada (where he now resides).
He completed a degree at the University of Lethbridge, in Computer Science; worked for the University of Wisconsin-Madison in the Computer Sciences Department as a Systems Programmer for the
Condor Research Project[
^]; and is currently completing another degree at the University of Lethbridge, once again, in Computer Science.
Ben has been known to enjoy reading, watching movies, playing console games, and learning everything he can about computers. And, more importantly, with regards to his character: does not usually speaks about himself in the third person.