Non-pushbutton Controls in Toolbars

Several Windows application use toolbars, and I’m sure you have noticed that many of them place non-push-button items inside their toolbars.  A good example is WordPad which for instance has a combo box for selecting the font family inside its formatting toolbar.  Have you ever wondered how this is done?  This article explains the steps you need to place some kind of control inside a toolbar.  The control I have chosen here is a combo box, but you can perform similar steps to place any kind of control inside your toolbars.

  1. Create a toolbar (if you don’t have one already) inside the MSVC resource editor, and add any buttons to it, as you would make a normal toolbar.  Then, close the MSVC workspace, and open the .rc file containing the toolbar definition in some text editor capable of saving documents in plain text, NotePad being a good example.  Add a placeholder SEPARATOR item to the toolbar definition, so that the toolbar definition would look like this:

    IDR_MAINFRAME TOOLBAR DISCARDABLE  16, 15
    BEGIN
        BUTTON      ID_FILE_NEW
        BUTTON      ID_FILE_OPEN
        BUTTON      ID_FILE_SAVE
    	SEPARATOR
        BUTTON      ID_EDIT_CUT
        BUTTON      ID_EDIT_COPY
        BUTTON      ID_EDIT_PASTE
    	SEPARATOR
    	SEPARATOR  /* Place holder for the combo box */
    	SEPARATOR
        BUTTON      ID_FILE_PRINT
    	SEPARATOR
        BUTTON      ID_APP_ABOUT
    END
  2. Go to the Resource View, right click on the "MyApp resources" tree item, choose Resource Symbols, click the New button, and add a new resource symbol with an appropriate name, like IDC_COMBO.
  3. Derive a class from CToolBar using the Class Wizard, give it a reasonable name (like CExtendedToolBar) and add a CComboBox member variable to that class.  Then, override the CreateEx( ) member function of the class like this:
    BOOL CExtendedToolBar::CreateEx(CWnd* pParentWnd,
    DWORD dwCtrlStyle /* = TBSTYLE_FLAT*/,
    DWORD dwStyle /* = WS_CHILD | WS_VISIBLE | CBRS_ALIGN_TOP*/,
    CRect rcBorders /* = CRect(0, 0, 0, 0)*/,
    UINT nID /* = AFX_IDW_TOOLBAR*/,
    UINT nResourceID /* = IDR_MAINFRAME */)
    {
    if (!CToolBar::CreateEx( pParentWnd, dwCtrlStyle,
    dwStyle, rcBorders, nID ) ||
    !CToolBar::LoadToolBar( nResourceID ))
    return FALSE;

    const int nWidth = 150;
    const int nHeight = 200;

    const UINT nItemIndex = 8;

    SetButtonInfo( nItemIndex, IDC_COMBO, TBBS_SEPARATOR, nWidth );

    CRect rcItem;
    GetItemRect( nItemIndex, &rcItem );
    rcItem.bottom = rcItem.top + nHeight;

    if (!m_ComboBox.Create( WS_CHILD | WS_VISIBLE | WS_VSCROLL | CBS_DROPDOWNLIST,
    rcItem, this, IDC_COMBO ))
    {
    DestroyWindow();
    return FALSE;
    }

    return TRUE;
    }
  4. Make sure that the creation code for the toolbar is like this (no LoadToolbar( ) call is necessary):
        if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
    | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC))
    {
    TRACE0("Failed to create toolbar\n");
    return -1; // fail to create

    }
  5. Add a small member function to the CExtendedToolBar class that allows access to the member combo box object:
    CComboBox & CExtendedToolBar::GetComboBox()
    {
    return m_ComboBox;
    }
  6. Add a resource string in the form of "Status Text\nTooltip String" like a normal toolbar button.  The "Tooltip String" will appear as a tooltip when the mouse is over the combo box, and the "Status Text" will appear in the status bar.
  7. Handle any combo box notifications like normal.  These notifications should be handled inside the derived toolbar class.

Note that if you want to update the combo box contents according to your application’s state, the process is different from updating a normal toolbar button.  You need to override the virtual function OnUpdateCmdUI( ) inside the derived toolbar class, and first call the base class version, and then add any logic for updating the combo box.  This function will be called from CWinApp::OnIdle( ) and it’s the root of all ON_UPDATE_COMMAND_UI update handlers.  If you forget to call the base class version, then all the other update handlers will stop working, so watch out!

The sample application at the bottom of the article contains a working sample using the steps above.  Download it, and investigate it, it’s pretty easy!  So now you too can start having custom toolbars, happy toolbar-ing!

 Download source code for the article

This article originally appeared on BeginThread.com. It’s been republished here, and may contain modifications from the original article.

Posted in Visual C++