Exoware ....   Tech Notes    About Exoware    Home
 

Quality solutions, on time, and on budget

   

Tech Note 

Enhanced Flat ComboBox Control

Eric Hartwell - January, 2000

This article describes enhancements to the Kirk Stowell's Office Style Flat ComboBox control.

  1. The drop-down arrow can hide until the combo field is active (either selected or has focus).
     
  2. The foreground and background colors of the field may be changed dynamically.

 

Here is Kirk's original Office Style Flat ComboBox article as of December, 1999:

Office Style Flat ComboBox
Kirk Stowell
A drop-in replacement combobox that gives your apps the flat Office-style look

Sample Image - combobox_flatcombo.gif
This control easily gives your application the Flat Look that is seen in the Microsoft office products. To use the control, simply add the files CCJFlatComboBox.cpp and CCJFlatComboBox.h to your project. You can use Class Wizard to add the CCJFlatComboBox member variables ( you most likely will have to rebuild the .clw file associated with your project ), or just replace any instance of CComboBox, with CCJFlatComboBox.

Example

Below is an example of how you might add the control to your project.

Header file:

    
    //{{AFX_DATA(CFlatComboDemoDlg)  
        enum { IDD = IDD_FLATCOMBODEMO_DIALOG };  
        CCJFlatComboBox m_DDCombo;  
    //}}AFX_DATA  
     

Implementation file:

    
    //{{AFX_DATA_MAP(CFlatComboDemoDlg)  
        DDX_Control(pDX, IDC_DROPDOWN_COMBO, m_DDCombo);  
    //}}AFX_DATA_MAP  
     

Acknowledgements:

  • Chris Maunder - For letting me use his color picker class, and for his auto-completion code. I made some modifications to the appearance of the control that is used in this demo. My modifications are noted.
  • Gilberto Botaro - For his help with adding auto completion to the CCJFlatComboBox class.
  • Vachik Hovhannissian and Danilo Lax - For help with fixing focus and message handling bugs.
  • Yosh Yamashita - For help with fixing accelerator bug.
  • Shannon McCoy - For suggestions on using ::GetSysColor(...) and ::GetSystemMetrics(...) more efficiently.
  • Todd Brannam - For help with fixing offset bug to use GetSystemMetrics().

http://www.codeguru.com/combobox/FlatComboDemo.shtml
http://www.codeproject.com/combobox/combobox_flatcombo.asp

Copyright © Kirk Stowell, 1998-1999. All rights reserved

Drop-Down Arrow

Hiding the drop-down arrow is actually straightforward, since the CCJFlatComboBox code already overrides the standard button painting. We add a control switch, m_bHideButton, which tells the control whether to paint the button or not.

void CCJFlatComboBox2::ShowButton(BOOL bShow /*= TRUE*/)
{
    m_bHideButton = ! bShow;
}

If the control is inactive, we simply paint over it using the control's background color.

switch (eState)
{
    case normal:
        rcItem.top -= 1;
        rcItem.bottom += 1;

        // 991018 Hartwell - hide the button unless selected
        if (m_bHideButton)
        {
            rcItem.left -= 1;
            pDC->FillSolidRect(rcItem, m_clrBack);
        }
        else // Display the button as per original code
        {
            pDC->Draw3dRect(rcItem, ::GetSysColor(COLOR_BTNHIGHLIGHT),
                                    ::GetSysColor(COLOR_BTNHIGHLIGHT));
            rcItem.left -= 1;
            pDC->Draw3dRect(rcItem, ::GetSysColor(COLOR_BTNHIGHLIGHT),
                                    ::GetSysColor(COLOR_BTNHIGHLIGHT));
        }
        break;

We also need to hide the arrow when the control is disabled:

if (!IsWindowEnabled())
{
    if (m_bHideButton)                         // 991019 hide button when disabled
    {
        rcItem.InflateRect(1, 1, 0, 1);        // Cover the remaining button
        pDC->FillSolidRect(rcItem, m_clrBack); // .. and hide it
    }
    ReleaseDC(pDC);
    return;
}

Finally, we need to force repaint on MouseOver and on SetFocus, so that the previously hidden button is now displayed.

if (m_bHideButton)  Invalidate();         // 19991019 force repaint of button

 

Text and Background Colors

Dynamically changing the control's colors is a little trickier. The problem here is that Windows paints the edit box and the combo box parts of the control separately:

Q81707 - INFO: WM_CTLCOLOR Processing for Combo Boxes of all Styles
Windows sends a WM_CTLCOLOR message to the parent of a control window to enable the parent to specify the color of the control. ... Windows does not define a notification code that enables an application to change the color of a combo box control. However, Windows sends WM_CTLCOLOR messages to a combo box control that relate to its component parts: one message for the list box portion and, if applicable, another message for the edit control portion. An application can subclass the control to intercept and process these messages.

We set the colors by intercepting the CtlColor message for the combo box, and the reflected OnCtlColor message for the edit box. (see TN062: Message Reflection for Windows Controls, and Q148242 - HOWTO: Handle OCM_CTLCOLORxxx Reflected Messages):

// 19991019 Hartwell - this sets the color of the combo box part of the control
HBRUSH CCJFlatComboBox2::CtlColor(CDC* pDC, UINT nCtlColor)
{
    pDC->SetTextColor(m_clrText);
    pDC->SetBkColor(m_clrBack);
    return(m_brBack);              // ctl bkgnd
}

// 19991019 Hartwell - this sets the color of the edit box part of the control
HBRUSH CCJFlatComboBox2::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
{
    return(CtlColor(pDC, nCtlColor));
}

We also add methods to set the colors dynamically. Note that changing the background color requires creating a new brush.

void CCJFlatComboBox2::SetTextColor(COLORREF cColor)
{
    m_clrText = cColor;
}

void CCJFlatComboBox2::SetBackColor(COLORREF cColor)
{
    m_clrBack = cColor;
    m_brBack.DeleteObject();
    m_brBack.CreateSolidBrush( m_clrBack );
}

Revisions:

  1. January, 2000 - Initial version


Send mail to webmaster@exoware.com with questions or comments about this web site.
Copyright © 1997-2005 Exoware. Last modified: March 16, 2005