Introduction
Groupboxes are one of my favorite UI elements. They collect together related controls, and guide the user through non-trivial user interfaces. It seems natural to display an icon in the groupbox header, since studies have shown that graphic images are more quickly recognized by users.
This control implements two styles of groupboxes: a standard groupbox that allows you to display text and/or an icon; and a header-only groupbox, which offers same features, but only displays a single line, rather than a frame. The header-only style offers advantages when used in a very compressed UI, since it requires less screen real estate.
Features
Here are features which
XGroupBox implements:
|
Replacement for Win32 groupbox, without the flicker when resized |
|
Display icon and/or text |
|
Display standard groupbox or header-only groupbox |
|
Easy to set colors, font, and horizontal alignment |
|
Support theming or custom colors (for header-only style, theming is not supported) |
|
Allow for disabling of control and optionally disabling all child controls contained within groupbox |
|
When control is disabled, icon will be displayed in grayscale |
XGroupBox Demo
The demo app shows some examples of what this control can do:
This dialog is resizable and shows difference in flickering between XGroupBox and Win32 groupbox.
Header-Only Style
A separate dialog shows how header-only style may be used:
XGroupBox Example Gallery
There is another dialog that runs through different option settings and shows you the code used to generate the
XGroupBox that is being displayed:
XGroupBox API
Function |
Description |
CXGroupBox& EnableTheme(BOOL bEnable, BOOL bRedraw = TRUE) |
Enables/disables use of themes (if available) |
BOOL EnableWindow(BOOL bEnable = TRUE, BOOL bRecurseChildren = FALSE) |
Enables/disables control, and optionally its children |
ALIGNMENT GetAlignment() |
Retrieves control alignment; this is alignment of text and icon |
BOOL GetBold() |
Retrieves bold setting |
COLORREF GetBorderColor() |
Retrieves border color |
BORDER_STYLE GetBorderStyle() |
Retrieves border style (flat or etched) |
BOOL GetDisabledStyle() |
Returns TRUE if control will display disabled state |
CFont* GetFont() |
Retrieves pointer to CFont member variable |
BOOL GetFont(LOGFONT *pLF) |
Retrieves LOGFONT struct for font |
CString GetFontFaceName() |
Retrieves font face name |
int GetFontPointSize() |
Retrieves font point size |
ALIGNMENT GetIconAlignment() |
Retrieves icon alignment (left or right of text) |
int GetIconSpacing() |
Retrieves spacing between icon and text |
void GetMargins(int& nXMargin, int& nYMargin) |
Retrieves x and y margins |
CONTROL_STYLE GetControlStyle() |
Retrieves control style (groupbox or header) |
COLORREF GetTextColor() |
Retrieves text color |
CXGroupBox& SetAlignment(ALIGNMENT eAlign, BOOL bRedraw = TRUE) |
Sets control alignment (for text and icon) |
CXGroupBox& SetBold(BOOL bBold, BOOL bRedraw = TRUE) |
Sets bold font |
CXGroupBox& SetBorderColor(COLORREF crBorder, BOOL bRedraw = TRUE) |
Sets border color |
CXGroupBox& SetBorderStyle(BORDER_STYLE eStyle, BOOL bRedraw = TRUE) |
Sets border style (flat or etched) |
CXGroupBox& SetControlStyle(CONTROL_STYLE eStyle, BOOL bRedraw = TRUE) |
Sets control style (groupbox or header) |
CXGroupBox& SetDisabledStyle(BOOL bShowDisabledState, BOOL bRedraw = TRUE) |
Sets whether control will display disabled state |
CXGroupBox& SetFont(CFont *pFont, BOOL bRedraw = TRUE) |
Sets font via CFont object |
CXGroupBox& SetFont(LOGFONT * pLogFont, BOOL bRedraw = TRUE) |
Sets font via LOGFONT struct |
CXGroupBox& SetFont(LPCTSTR lpszFaceName, int nPointSize, BOOL bRedraw = TRUE) |
Sets font face name and point size |
CXGroupBox& SetIcon(HICON hIcon, UINT nIconSize = 16, BOOL bRedraw = TRUE) |
Sets icon via HICON |
CXGroupBox& SetIcon(UINT nIconId, UINT nIconSize = 16, BOOL bRedraw = TRUE) |
Sets icon via resource id |
CXGroupBox& SetIconAlignment(ALIGNMENT eAlign, BOOL bRedraw = TRUE) |
Sets icon alignment (left or right of text) |
CXGroupBox& SetIconSpacing(int nIconSpacing, BOOL bRedraw = TRUE) |
Sets spacing between icon and text |
CXGroupBox& SetImageList(CImageList * pImageList, int nIconNo, BOOL bRedraw = TRUE) |
Sets image list for icons |
CXGroupBox& SetMargins(int nXMargin, int nYMargin, BOOL bRedraw = TRUE) |
Sets x and y margins |
CXGroupBox& SetTextColor(COLORREF cr, BOOL bRedraw = TRUE) |
Sets text color |
CXGroupBox& SetWindowText(LPCTSTR lpszText, BOOL bRedraw = TRUE) |
Sets text |
How to Use
Step 1 - Add Files
To integrate XGroupBox into your app, you first need to add following files to your project:
- XGroupBox.cpp
- XGroupBox.h
- XVisualStyles.h
Step 2 - Add Header File to Your Source Module
In the module where you want to use
XGroupBox (typically this will be dialog header file), include header file
XGroupBox.h.
Step 3 - Add Button Control to Dialog
Using the VS IDE resource editor, add a static control where you want the
XGroupBox control. Here is a portion of the
.rc file for demo app:
LTEXT "XGroupBox 1",IDC_GROUPBOX1,10,146,110,32
LTEXT "Danger Will Robinson!",IDC_STATIC,43,165,73,8
LTEXT "XGroupBox 2",IDC_GROUPBOX2,130,146,100,32
LTEXT "~ My Music ~",IDC_STATIC,164,165,45,8
LTEXT "XGroupBox 3",IDC_GROUPBOX3,10,183,220,42,0
LTEXT "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean nec neque eu.",
IDC_STATIC,18,202,132,17,NOT WS_GROUP
PUSHBUTTON "Button",IDC_BUTTON2,165,201,50,14
LTEXT "XGroupBox 4",IDC_GROUPBOX4,10,230,220,42
LTEXT "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean nec neque eu.",
IDC_STATIC,18,249,132,17,NOT WS_GROUP
PUSHBUTTON "Button",IDC_BUTTON3,165,248,50,14
Note that all the static controls use the LTEXT
tag - the alignment of text and icon is done with the SetAlignment()
function.
Next, associate static control with CStatic
class variable. Then replace CStatic
with CXGroupBox
:
// Dialog Data
//{{AFX_DATA(CXGroupBoxTestDlg)
enum { IDD = IDD_XGROUPBOXTEST_DIALOG };
CXGroupBox m_XGroupBox1;
CXGroupBox m_XGroupBox2;
CXGroupBox m_XGroupBox3;
CXGroupBox m_XGroupBox4;
int m_nStyle;
int m_nAlign;
int m_nColor;
BOOL m_bEnableThemes;
BOOL m_bDisable;
int m_nBorderStyle;
//}}AFX_DATA
Step 4 - Add Initialization Code
Add initialization code to your
OnInitDialog()
function. In demo app, one-time initialization is performed in
OnInitDialog()
:
// one-time initialization
m_XGroupBox1.SetTextColor(RGB(255,0,0), FALSE)
.SetBold(TRUE, FALSE);
m_XGroupBox2.SetTextColor(RGB(34,139,34), FALSE) // forestgreen
.SetBold(TRUE, FALSE)
.SetFont(_T("Comic Sans MS"), 10, FALSE)
.SetAlignment(CXGroupBox::right);
m_XGroupBox3.SetAlignment(CXGroupBox::center);
m_XGroupBox4.SetFont(_T("Comic Sans MS"), 14, FALSE);
Dynamic initialization is performed in
OnChange()
:
//=============================================================================
void CXGroupBoxTestDlg::OnChange()
//=============================================================================
{
UpdateData(TRUE);
if (m_hGlobeIcon)
::DestroyIcon(m_hGlobeIcon);
m_hGlobeIcon = 0;
static UINT nIconId[] = { IDI_T256, IDI_T32BPP };
static CXGroupBox *pControls[4] = { &m_XGroupBox1, &m_XGroupBox2,
&m_XGroupBox3, &m_XGroupBox4 };
int i = 0;
int nSize = m_nColor ? 32 : 16;
if (m_nStyle == 0 || m_nStyle == 2)
{
// Note: you can also use LoadIcon(), if you are sure that
// you will get correct icon
m_hGlobeIcon = (HICON) ::LoadImage(AfxGetInstanceHandle(),
MAKEINTRESOURCE(nIconId[m_nColor]),
IMAGE_ICON, nSize, nSize, LR_DEFAULTCOLOR);
ASSERT(m_hGlobeIcon);
}
if (m_hGlobeIcon)
{
CImageList list;
VERIFY(list.Create(nSize, nSize, ILC_COLOR32|ILC_MASK, 2, 1));
VERIFY(list.Add(m_hGlobeIcon) == 0);
m_XGroupBox1.SetIcon(IDI_REDX, 32, FALSE);
m_XGroupBox2.SetIcon(IDI_AUDIOCD, 32, FALSE);
m_XGroupBox3.SetImageList(&list, 0, FALSE);
m_XGroupBox4.SetImageList(&list, 0, FALSE);
}
else
{
// no icon
for (i = 0; i < 4; i++)
pControls[i]->SetIcon((HICON)0, nSize, FALSE);
}
for (i = 0; i < 4; i++)
{
CString str = _T("");
if (m_nStyle == 0 || m_nStyle == 1)
str.Format(_T("XGroupBox %d"), i+1);
pControls[i]->SetWindowText(str);
}
if (m_nStyle == 0 || m_nStyle == 1)
m_XGroupBox3.SetWindowText(MAKEINTRESOURCE(IDS_GROUPBOX3_TEXT), FALSE);
CXGroupBox::ALIGNMENT eAlign = CXGroupBox::left;
if (m_nAlign)
eAlign = CXGroupBox::right;
for (i = 0; i < 4; i++)
pControls[i]->SetIconAlignment(eAlign, FALSE);
for (i = 0; i < 4; i++)
pControls[i]->SetBorderStyle((CXGroupBox::BORDER_STYLE) m_nBorderStyle, FALSE);
RedrawWindow();
for (i = 0; i < 4; i++)
pControls[i]->RedrawWindow();
}
References
More Groupbox Control Articles
Revision History
Version 1.0 - 2008 September 2
Usage
This software is released into the public domain. You are free to use it in any way you like, except that you may not sell this source code. If you modify it or extend it, please to consider posting new code here for everyone to share. This software is provided "as is" with no expressed or implied warranty. I accept no liability for any damage or loss of business that this software may cause.