Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

.NET

Adding a Combo Box to a Toolbar


When toolbars first appeared in Windows applications, they were commonly assumed to be simple shortcuts to functionality that appeared in the menus. The concept was that a user would (over time) associate a menu item and a toolbar button icon (image) and begin to use the toolbar button instead of the menu item. This had the effect of greatly increasing user productivity for many common tasks like opening a file, saving a file, etc.

Life was good…

Then nonbutton controls started creeping into toolbars in Microsoft Office applications in particular. A good example is the Find Text feature. Originally, an icon (typically a pair of binoculars) would appear on the toolbar. When clicked, the Find Text dialog would appear with a range of options for the user — case-sensitivity, search direction, wildcards, etc. However, most of the time, a user simply wanted to find a string in the file and didn’t care to deal with all of the features presented by the dialog. The user simply wanted to find the string as quickly as possible. So, a search text combo box was added to the toolbar. When text was entered into the edit area of the combo box and the Enter key was pressed, the application would typically search the active document for a match. The most common options for searching were assumed — case-insensitive, search forward, no wildcards. If the user clicked the drop-down button on the combo box, a list of recently entered find strings was displayed, allowing for easier reuse of past search values.

When all of this started happening, I remember more than one discussion with engineers I worked with who believed that the whole idea of putting nonbutton controls on a toolbar was a real violation of the intent of a toolbar — that it should be an iconic version of menu items. One reasonable complaint was that it cluttered up the toolbar since these combo boxes took up a great deal of space relative to normal toolbar buttons. However, time passed and nonbutton controls became much more common on toolbars. If used judiciously, they can be a real time saver for users and when you get down to it, that’s what toolbars were really intended for — a list of commonly used features that could be accessed quickly.

If you’ve worked very much with toolbars in Visual Studio (even the newer .NET versions), you’ve probably noticed that the editor doesn’t have any native support for dropping nonbutton controls like combo boxes on a toolbar. Fortunately, it is possible to do this and it turns out to be quite straightforward.

First, consider the following main window from a simple MFC application I created:

This is a plain-old baseline MFC application created using App Wizard with one modification: I added a new toolbar button at the end of the toolbar. It’s the one that looks like the letter “X”. Creating this extra button is the first step in putting a control on the toolbar. To be fair, you could create a nonbutton control without doing this step, but I think it’s easier to do it this way since you get to use the Visual Studio Resource Editor to visually position the control.

The next step is to derive a new version of the MFC toolbar class CToolBar. I called mine CEnhancedToolBar. Within this class, I created a method to allow for creating a single combo box given a toolbar button ID and an ID for the new combo box. Here is what that code looks like:

bool CEnhancedToolBar::CreateCombo( int nToolBarBtnID,int nComboID )
{
    // only allow a single call to this method since we can only
    // handle a single combo box.
    if ( ::IsWindow(m_combo.m_hWnd) )
         return false;
    // Create the combo box
    int nIdx = CommandToIndex(nToolBarBtnID);
    ASSERT( nIdx >= 0 );
    SetButtonInfo(nIdx, nComboID, TBBS_SEPARATOR, 150);
    const int nDropHeight = 100;
    CRect rect;
    GetItemRect(nIdx, &rect);
    rect.top = 1;
    rect.bottom = rect.top + nDropHeight;
if (!m_combo.Create(CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_TABSTOP | WS_CHILD, rect, this, nComboID))
    {
        TRACE0("Failed to create combobox in ToolBar\n");
        return false;
    }
    // update the combo with a font.
    m_font.CreatePointFont( 80,"MS Sans Serif" );
    m_combo.SetFont( &m_font ); 
    // show the combobox.
    m_combo.ShowWindow( SW_SHOWNORMAL );
    return true;
}

After making sure this method is only called once, the first step is to find the toolbar button that we want to replace and change its type to be a Separator. This allows the toolbar button to be used to separate the new combo box from surrounding buttons and looks better visually. Then, the combo box is created just as you would create any MFC CComboBox object. Notice that the combo box uses the toolbar as its parent as you would expect. Then, I gave the combo box its own font object to make it look nicer (yes, if I was doing this in a real app, I’d query the current Windows System properties to take into account overrides for control fonts, but you get the idea). Finally, I show the combo box on the toolbar.

Back in MainFrm.cpp where the toolbar is created, I added a few lines of code to insert some items into the combo box just for fun:

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
        return -1;

    if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | 
WS_VISIBLE | CBRS_TOP
        | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY |
 CBRS_SIZE_DYNAMIC) ||
       !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
    {
        TRACE0("Failed to create toolbar\n");
        return -1;      // fail to create
     }

    
    const int ID_COMBO_BOX = 2000;
    if ( m_wndToolBar.CreateCombo( ID_COMBO_BOX_BTN,ID_COMBO_BOX) )
     {
        CComboBox& box = m_wndToolBar.GetCombo();
        box.AddString( "blue" );
        box.AddString( "green" );
        box.AddString( "yellow" );    
        box.SetCurSel(1);
     }

        // addl init stuff follows...
}

Finally, here is what the toolbar with the new combo box looks like:

And one final look with the box dropped down:

Since the combo box is parented to the toolbar, all of its notification messages will go to the toolbar. So if you want those notifications to be processed by the main window (or some other code), you'll need to add some more support in CEnhancedToolBar to pass those notifications on to the interested party. An exercise left for the reader is improving the CEnhancedToolBar class so that it supports creating any number of CComboBox objects on the toolbar (not just a single one).

At this point, it should be clear that adding nonbuttons to toolbars is really simple. If you have a Find feature in your application, there's no reason not to include a combo box Find control on your toolbar, too. Your users will thank you.


Mark M. Baker is the Chief of Research & Development at BNA Software located in Washington, D.C. He can be contacted at [email protected].


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.