Click here to Skip to main content
15,908,768 members
Articles / Desktop Programming / MFC
Article

Adding a drop arrow to a toolbar button

Rate me:
Please Sign up or sign in to vote.
4.69/5 (20 votes)
15 Dec 1999 663.6K   2.2K   69   46
Demonstrates how to use the new toolbar styles to add dropdown arrows to toolbar buttons
  • Download demo project - 28 Kb
  • Sample Image - toolbar_droparrow.gif

    If you wanted to add a drop menu like the ones seen in internet explorer, it is pretty straight forward. This approach for will work for both Visual C++ 5 and 6, however you may want to read up on the enhancements to the toolbar class for VC 6.0.

    First off, after your toolbar has been created in CMainFrame::OnCreate(), you will need to make a call to the following

    DWORD dwExStyle = TBSTYLE_EX_DRAWDDARROWS;
    m_wndToolBar.GetToolBarCtrl().SendMessage(TB_SETEXTENDEDSTYLE, 0, (LPARAM)dwExStyle);

    This will enable your toolbar to handle drop arrows. The next thing you will need to do, is to actually add the drop arrow to your desired button. This will be done via the SetButtonStyle() method:

    DWORD dwStyle = m_wndToolBar.GetButtonStyle(m_wndToolBar.CommandToIndex(ID_FILE_OPEN));
    dwStyle |= TBSTYLE_DROPDOWN;
    m_wndToolBar.SetButtonStyle(m_wndToolBar.CommandToIndex(ID_FILE_OPEN), dwStyle);

    Now, you will need to add a message handler for the drop arrow, as well a menu to the application resources. Assuming you already know how to create a menu, ( if not, click on the resource tab, select the resource name ie: MyApp Resources, then right click. Select insert, then select Menu, then press the New button ) and assuming that the resource id for our menu is IDR_MENU1, add the following code to CMainFrame's message map:

    BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
    	//{{AFX_MSG_MAP(CMainFrame)
    	...
    	ON_NOTIFY(TBN_DROPDOWN, AFX_IDW_TOOLBAR, OnToolbarDropDown)
    	//}}AFX_MSG_MAP
    END_MESSAGE_MAP()

    Add the following method to CMainFrame's .cpp file:

    void CMainFrame::OnToolbarDropDown(NMTOOLBAR* pnmtb, LRESULT *plr)
    {
    	CWnd *pWnd;
    	UINT nID;
    
    	// Switch on button command id's.
    	switch (pnmtb->iItem)
    	{
    	case ID_FILE_OPEN:
    		pWnd = &m_wndToolBar;
    		nID  = IDR_MENU1;
    		break;
    	default:
    		return;
    	}
    	
    	// load and display popup menu
    	CMenu menu;
    	menu.LoadMenu(nID);
    	CMenu* pPopup = menu.GetSubMenu(0);
    	ASSERT(pPopup);
    	
    	CRect rc;
    	pWnd->SendMessage(TB_GETRECT, pnmtb->iItem, (LPARAM)&rc);
    	pWnd->ClientToScreen(&rc);
    	
    	pPopup->TrackPopupMenu( TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_VERTICAL,
    		rc.left, rc.bottom, this, &rc);
    }

    Then add the following to CMainFrame's .h file:

    //{{AFX_MSG(CMainFrame)
    ...
    afx_msg void OnToolbarDropDown(NMTOOLBAR* pnmh, LRESULT* plRes);
    //}}AFX_MSG
    

    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


    Written By
    CEO Codejock Technologies, LLC
    United States United States
    This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.
    This is a Organisation (No members)


    Comments and Discussions

     
    QuestionDropdown arrow on the bottom of the button Pin
    Bruno Scopigno28-Mar-12 5:04
    Bruno Scopigno28-Mar-12 5:04 
    QuestionImplementing windows explorer 'views' type of menu Pin
    SharanyaMahi5-Dec-11 20:20
    SharanyaMahi5-Dec-11 20:20 
    Generaldropdown toolbar instead of menu Pin
    mimosa22-Jun-10 11:21
    mimosa22-Jun-10 11:21 
    QuestionHow do I add menu item function and update function for multiple and dynamic menu items Pin
    akira3226-Oct-08 23:17
    akira3226-Oct-08 23:17 
    GeneralI used the vs2008 to compile the demo source code Pin
    akira3226-Oct-08 16:03
    akira3226-Oct-08 16:03 
    AnswerRe: I used the vs2008 to compile the demo source code Pin
    akira3226-Oct-08 17:21
    akira3226-Oct-08 17:21 
    GeneralBUG: CToolBar, drop-down, XP theme, and Internet Explorer Pin
    Damir Valiulin3-May-06 19:47
    Damir Valiulin3-May-06 19:47 
    GeneralMoving Arrow to Left of button Pin
    Hamid Reza Mohammadi2-Dec-05 5:12
    Hamid Reza Mohammadi2-Dec-05 5:12 
    Questionboth arrows and not? Pin
    noaa28-Jul-05 14:04
    noaa28-Jul-05 14:04 
    Generalreplacing button icons Pin
    Member 172228224-Feb-05 2:52
    Member 172228224-Feb-05 2:52 
    GeneralDrop Down Button in Internet Explorer Standard Toolbar Pin
    tunafish2410-Jan-04 9:26
    tunafish2410-Jan-04 9:26 
    GeneralRe: Drop Down Button in Internet Explorer Standard Toolbar Pin
    Bill SerGio, The Infomercial King4-Aug-04 4:29
    Bill SerGio, The Infomercial King4-Aug-04 4:29 
    GeneralRe: Drop Down Button in Internet Explorer Standard Toolbar Pin
    Alex (Swiftify)10-Sep-05 4:18
    Alex (Swiftify)10-Sep-05 4:18 
    GeneralCannot click arrow Pin
    pinguin75126-Jul-03 20:01
    pinguin75126-Jul-03 20:01 
    GeneralRe: Cannot click arrow Pin
    Tux9-Feb-04 15:26
    Tux9-Feb-04 15:26 
    GeneralRe: Cannot click arrow Pin
    rlaley18-Jan-05 22:34
    rlaley18-Jan-05 22:34 
    GeneralRe: Cannot click arrow Pin
    Rummey13-Mar-05 7:04
    Rummey13-Mar-05 7:04 
    GeneralRe: Cannot click arrow Pin
    Kirk Stowell14-Mar-05 4:21
    Kirk Stowell14-Mar-05 4:21 
    GeneralRe: Cannot click arrow Pin
    Rummey14-Mar-05 5:35
    Rummey14-Mar-05 5:35 
    GeneralRe: Cannot click arrow Pin
    Kirk Stowell14-Mar-05 10:21
    Kirk Stowell14-Mar-05 10:21 
    GeneralRe: Cannot click arrow Pin
    Rummey14-Mar-05 10:55
    Rummey14-Mar-05 10:55 
    GeneralRe: Cannot click arrow Pin
    Kirk Stowell15-Mar-05 4:29
    Kirk Stowell15-Mar-05 4:29 
    Hi Mike,

    If you are handling the message in an owner window such as CMainFrame then you would use ON_NOTIFY because the toolbar sends the TBN_DROPDOWN message to the owner window to "notify" the owner of the event that occured. If you are handling the message in a derived class then you would need to use ON_NOTIFY_REFLECT instead of ON_NOTIFY. If you want to use a derived class then I would suggest using CToolBar instead of CToolBarCtrl.

    Here is an example of how you would implement this.

    ToolBarEx.h:

    // ToolBarEx.h : header file
    //
    #if !defined(__TOOLBAREX_H__)
    #define __TOOLBAREX_H__
    
    #if _MSC_VER > 1000
    #pragma once
    #endif // _MSC_VER > 1000
    
    #include <afxtempl.h>
    
    /////////////////////////////////////////////////////////////////////////////
    // CToolBarEx window
    
    class CToolBarEx : public CToolBar
    {
    public:
        CToolBarEx();
        virtual ~CToolBarEx();
    
    public:
        //{{AFX_VIRTUAL(CToolBarEx)
        //}}AFX_VIRTUAL
        void SetDropArrow(UINT nCmdID, UINT nMenuID);
    
    protected:
        virtual void ShowPopupMenu(UINT nCmdID);
        
        //{{AFX_MSG(CToolBarEx)
        afx_msg void OnTBDropDown(NMTOOLBAR* pNMTB, LRESULT *pResult);
        //}}AFX_MSG
    
        DECLARE_MESSAGE_MAP()
    
        CMap<UINT, UINT, UINT, UINT> m_mapCmd2Mnu;
    };
    
    /////////////////////////////////////////////////////////////////////////////
    
    //{{AFX_INSERT_LOCATION}}
    // Microsoft Visual C++ will insert additional declarations immediately before the previous line.
    
    #endif // !defined(__TOOLBAREX_H__)


    ToolBar.cpp:

    // ToolBarEx.cpp : implementation file
    //
    
    #include "stdafx.h"
    #include "Resource.h"
    #include "ToolBarEx.h"
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
    
    /////////////////////////////////////////////////////////////////////////////
    // CToolBarEx
    
    CToolBarEx::CToolBarEx()
    {
    }
    
    CToolBarEx::~CToolBarEx()
    {
    }
    
    BEGIN_MESSAGE_MAP(CToolBarEx, CToolBar)
        //{{AFX_MSG_MAP(CToolBarEx)
        ON_NOTIFY_REFLECT(TBN_DROPDOWN, OnTBDropDown)
        //}}AFX_MSG_MAP
    END_MESSAGE_MAP()
    
    /////////////////////////////////////////////////////////////////////////////
    // CToolBarEx message handlers
    
    void CToolBarEx::ShowPopupMenu(UINT nCmdID)
    {
        UINT nMenuID;
        if (!m_mapCmd2Mnu.Lookup( nCmdID, nMenuID ))
            return;
    
        CMenu menu;
        if ( menu.LoadMenu( nMenuID ))
        {
            CMenu* pPopup = menu.GetSubMenu( 0 );
            ASSERT( pPopup );
    
            CRect rc;
            SendMessage( TB_GETRECT, nCmdID, ( LPARAM )&rc );
            ClientToScreen( &rc );
    
            pPopup->TrackPopupMenu( TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_VERTICAL,
                rc.left, rc.bottom, this, &rc );
        }
    }
    
    void CToolBarEx::OnTBDropDown(NMTOOLBAR* pNMTB, LRESULT *pResult)
    {
        ShowPopupMenu( pNMTB->iItem );
        *pResult = 0;
    }
    
    void CToolBarEx::SetDropArrow(UINT nCmdID, UINT nMenuID) 
    {
        int iItem = CommandToIndex( nCmdID );
        if (iItem != -1)
        {
            GetToolBarCtrl( ).SendMessage( TB_SETEXTENDEDSTYLE, 0,
                ( LPARAM )TBSTYLE_EX_DRAWDDARROWS );
            
            SetButtonStyle( iItem, 
                GetButtonStyle( iItem ) | TBSTYLE_DROPDOWN );
    
            m_mapCmd2Mnu.SetAt(nCmdID, nMenuID);
        }
    }


    Now in your CMainFrame class all you need to do is call SetDropArrow for as many command + menu combinations you wish to add, for example:

    m_wndToolBar.SetDropArrow( ID_FILE_NEW,  IDR_MENU1 );
    m_wndToolBar.SetDropArrow( ID_FILE_OPEN, IDR_MENU2 );


    Let me know if this helps.

    Kirk Stowell
    Codejock Software
    www.codejock.com
    GeneralRe: Cannot click arrow Pin
    Rummey15-Mar-05 4:53
    Rummey15-Mar-05 4:53 
    GeneralRe: Cannot click arrow Pin
    Kirk Stowell15-Mar-05 5:06
    Kirk Stowell15-Mar-05 5:06 
    GeneralRe: Cannot click arrow Pin
    CodeHead2-Sep-05 8:50
    CodeHead2-Sep-05 8:50 

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

    Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.