Enhanced Flat ComboBox Control
Eric Hartwell - January, 2000
This article describes enhancements to the Kirk Stowell's Office Style
Flat ComboBox control.
- The drop-down arrow can hide until the combo field is active (either
selected or has focus).
- 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
|
|
|

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().
|
|
|
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:
- January, 2000 - Initial version
|