XIcon - an MFC control to display text and icon






4.90/5 (20 votes)
XIcon is an MFC control that displays text and/or icon with auto-sizing.
Introduction
One of my clients recently showed me a competitor's product that had some very nice user interface features. One of the features was a groupbox that displayed a dynamic header and icon - the icon changed to indicate current status of the information displayed inside the groupbox. I thought this would be trivial to copy, so naturally I said I could do it.
Of course I was thinking of the trick I used with displaying a checkbox
in the groupbox header, like I did in my
EnableGroupboxControls
article. By placing a checkbox control over the groupbox header, but
after the groupbox control in tab order, it is possible to make
the checkbox appear to be integrated with the groupbox. My plan was to
do the same thing to display an icon and text over the groupbox header, using
a simple CStatic
-based control.
The result looked very good. I cannot show you how it looked, because I
scrapped this idea in about five seconds. Unlike user-interactive controls
(like buttons), CStatic
controls are assumed not to
change, and this meant that paint messages were not being sent to
CStatic
control in a consistent manner, causing icon
and text to suddenly disappear.
Since this is the way non-interactive controls behaved, my next choice
was to base the new icon control on CButton
. Making the
button ownerdraw and putting all the display code in the
DrawItem()
function, I quickly came up with CXIcon,
which proved to be stable and without the painting problems of earlier
CStatic
control.
CButton
, XIcon
objects do not act like buttons, and they do not display the usual
hot or pressed state.
XIcon Features and Behaviors
The XIcon demo app shows how XIcon control may be used with groupbox:
|
This screenshot shows some of the text effects and icon alignments.
XIcon buttons 1 and 2 use
BS_LEFT , and
XIcon buttons 3 and 4 use BS_RIGHT .
The bar that is placed inside each groupbox shows the width of the XIcon button as it is in the dialog template. In this screenshot, automatic resizing is turned on, and so the XIcon button resizes itself to the width of the text and icon. |
|
In this screenshot the XIcon buttons do not resize themselves.
The areas outlined in red show the over-sizing or under-sizing,
which correspond to the size of the bar placed inside the groupbox.
|
XIcon API
Function | Description |
---|---|
BOOL GetAutoResize() | Retrieves auto resize setting |
BOOL GetBold() | Retrieves bold setting |
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 |
int GetIconSpacing() | Retrieves spacing between icon and text |
void GetMargins(int& nXMargin, int& nYMargin) | Retrieves x and y margins |
COLORREF GetTextColor() | Retrieves text color |
void Resize() | Resize control based on current text, font, and icon setting |
CXIcon& SetAutoResize(BOOL bAutoResize, BOOL bRedraw = TRUE) | Sets auto resizing option |
CXIcon& SetBold(BOOL bBold, BOOL bRedraw = TRUE) | Sets bold font |
CXIcon& SetFont(CFont *pFont, BOOL bRedraw = TRUE) | Sets font via CFont object |
CXIcon& SetFont(LOGFONT * pLogFont, BOOL bRedraw = TRUE) | Sets font via LOGFONT struct |
CXIcon& SetFont(LPCTSTR lpszFaceName, int nPointSize, BOOL bRedraw = TRUE) | Sets font face name and point size |
CXIcon& SetIcon(HICON hIcon, UINT nIconSize = 16, BOOL bRedraw = TRUE) | Sets icon via HICON |
CXIcon& SetIcon(UINT nIconId, UINT nIconSize = 16, BOOL bRedraw = TRUE) | Sets icon via resource id |
CXIcon& SetIconSpacing(int nIconSpacing, BOOL bRedraw = TRUE) | Sets spacing between icon and text |
CXIcon& SetMargins(int nXMargin, int nYMargin, BOOL bRedraw = TRUE) | Sets x and y margins |
CXIcon& SetTextColor(COLORREF cr, BOOL bRedraw = TRUE) | Sets text color |
CXIcon& SetWindowText(LPCTSTR lpszText, BOOL bRedraw = TRUE) | Sets text |
Implementation Details
I have already mentioned that XIcon is based on ownerdrawCButton
control, and uses DrawItem()
function to
implement drawing. To reduce flicker to minimum, I also used
DC double-buffering when drawing text and icon.
In demo app, I have used file globe.ico that I extracted from image library that is included with Visual Studio®. This library (VS2005ImageLibrary.zip) is located in Common7 directory.
The only other thing you should be aware of is that you can supply icon to
XIcon either by passing HICON
handle, or by passing
resource id of icon. If passing icon, it is up to caller to make
sure icon is destroyed; if passing resource id, XIcon
will call DestroyIcon()
itself.
Note that there is no linkage between XIcon buttons and groupboxes. Here is dialog template for demo app, with groupbox/XIcon pairs highlighted:
How to use
Step 1 - Add Files
To integrate XIcon into your app, you first need to add following files to your project:
- XIcon.cpp
- XIcon.h
Step 2 - Add Header File to Your Source Module
In the module where you want to use XIcon (typically this will be dialog header file), include header file XIcon.h .
Step 3 - Add Button Control to Dialog
Using the VS IDE resource editor, add a button control where you want the XIcon control (make sure to selectBS_OWNERDRAW
style),
and associate button control
with a class variable. Then replace CButton
with
CXIcon
:
Step 4 - Add Initialization Code
Add initialization code toOnInitDialog()
function:
m_IconButton1.SetBold(TRUE, FALSE); // because no other attributes are being set, // it is necessary to tell control to resize itself m_IconButton2.Resize(); m_IconButton3.SetFont(_T("Comic Sans MS"), 10, FALSE); m_IconButton4.SetWindowText(MAKEINTRESOURCE(IDS_BUTTON_4), FALSE) .SetTextColor(RGB(0,0,255), FALSE); LoadIcons();
LoadIcons()
is function to load selected icon:
void CXIconTestDlg::LoadIcons() { UpdateData(TRUE); if (m_hGlobeIcon) ::DestroyIcon(m_hGlobeIcon); m_hGlobeIcon = 0; static UINT nIconId[] = { IDI_T256, IDI_T32BPP }; 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_nIconType]), IMAGE_ICON, 16, 16, 0); ASSERT(m_hGlobeIcon); } m_IconButton1.SetIcon(m_hGlobeIcon); m_IconButton2.SetIcon(m_hGlobeIcon); m_IconButton3.SetIcon(m_hGlobeIcon); // pass icon resource id m_IconButton4.SetIcon(m_nStyle == 1 ? 0 : nIconId[m_nIconType]); }
Revision History
Version 1.0 - 2008 May 4
- Initial public release
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.