WTL Tool Bar Drop-Down Extension

Environment: VC++ 6.0, Win2K, NT 4.0 SP6 and Win98
Note: You also need to download the Windows Template Library (WTL) from the Platform SDK (April 2000)

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 processes 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& /*bHandled*/)
{
 //...
		
 // Subclass parent window
 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) // Parent window messages
 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 /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
{
 LPNMTOOLBAR lpnmtb = (LPNMTOOLBAR)pnmh;	

 // Check if this is from us
 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;
}

// Do not hot track if application in background
LRESULT OnParentHotItemChange(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
{
 LPNMTBHOTITEM lpnmhi = (LPNMTBHOTITEM)pnmh;

 // Check if this is from us
 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 /*uMsg*/, WPARAM /*wParam*/, 
                  LPARAM /*lParam*/, BOOL& /*bHandled*/)
 {
  //...

  // HWND hWndToolBar = CreateSimpleToolBarCtrl(m_hWnd, 
                                                IDR_MAINFRAME, 
                                                FALSE, 
                                                ATL_SIMPLE_TOOLBAR_PANE_STYLE);

  HWND hWndToolBar = m_wndToolBar.Create(m_hWnd, 
                                         rcDefault, 
                                         NULL, 
                                         ATL_SIMPLE_TOOLBAR_PANE_STYLE);

  // Load the toolbar
  m_wndToolBar.LoadToolBar(IDR_MAINFRAME); 

  
  // Load all the menu images were going to need
  m_wndToolBar.LoadMenuImages(IDR_MAINFRAME); 
  
  // Add some drop-down buttons
  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!.

Version 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.

Downloads

Download demo project - 112 Kb
Download source - 4 Kb


Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: March 19, 2015 @ 1:00 p.m. ET / 10:00 a.m. PT The 2015 Enterprise Mobile Application Survey asked 250 mobility professionals what their biggest mobile challenges are, how many employees they are equipping with mobile apps, and their methods for driving value with mobility. Join Dan Woods, Editor and CTO of CITO Research, and Alan Murray, SVP of Products at Apperian, as they break down the results of this survey and discuss how enterprises are using mobile application management and private …

  • On-demand Event Event Date: February 12, 2015 The evolution of systems engineering with the SysML modeling language has resulted in improved requirements specification, better architectural definition, and better hand-off to downstream engineering. Agile methods have proven successful in the software domain, but how can these methods be applied to systems engineering? Check out this webcast and join Bruce Powel Douglass, author of Real-Time Agility, as he discusses how agile methods have had a tremendous …

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date