Click here to Skip to main content
Click here to Skip to main content

XButtonXP - an XP-aware pushbutton that can also toggle and display an icon

, 19 Jan 2008
Rate this:
Please Sign up or sign in to vote.
XButtonXP is an XP theme-aware pushbutton that can optionally be used as a toggle button. It can also display an icon with or without text.

Introduction

Looking around for a theme-aware toggle button that could display text and an icon, I could not find one, so XButtonXP is the result: a pushbutton that can also be a toggle button, and can display icon and/or text.

What's New in v1.3

In this version I have corrected (I believe) all the outstanding bugs that have been reported (see list), and added several new features:

  • Grayscale icons - in previous version, icon on disabled button looked like this:

    screenshot

    In this version they look like:

    screenshot

  • Transparent background for toolbar style - the parent's background is shown when mouse is not hovering:

    No hover
    screenshot
    Hover
    screenshot
  • Multi-line text buttons - buttons with multiple lines of text are now supported using standard style BS_MULTILINE:

    screenshot

  • Custom text and background colors - custom colors may now be used for button text and background colors:

    screenshot

XButtonXP in Action

Here is what XButtonXP looks like with themes:
Icon on Left
screenshot
Icon on Right
screenshot
No Icon
screenshot
No Text
screenshot
Toggled
screenshot
Disabled
screenshot

And here is what XButtonXP looks like without themes:

Icon on Left
screenshot
Icon on Right
screenshot
No Icon
screenshot
No Text
screenshot
Toggled
screenshot
Disabled
screenshot

XButtonXP can also be drawn using toolbar style:

No Hover
screenshot
Hover
screenshot

CXButtonXP Implementation Notes

Theme Support

Normally, when you add manifest file to exe, all controls used by exe will be displayed as themed. However, this is not true of ownerdraw controls - the XP theming engine just ignores them. Since I needed an ownerdraw button, it meant that XButtonXP had to handle the XP theming support. I created the CXThemeHelper class to handle loading UXTHEME.DLL and getting theme function pointers via GetProcAddress(). To make CXThemeHelper lightweight and easy to reuse, I designed it as singleton class, so that there is only one copy of DLL's module handle and function pointers per process.

The first time that CXButtonXP::DrawItem() is called, the theme is opened for Button class:

    if (ThemeHelper.IsThemeLibAvailable())
    {
        m_hTheme = ThemeHelper.OpenThemeData(m_hWnd, _T("Button"));
    }

Aside from using theme functions for drawing the controls, one other thing CXButtonXP must do is handle WM_THEMECHANGED message, which is broadcast to every window following a theme change event:

case WM_THEMECHANGED:
{
    if (IsThemed())
    {
        if (m_hTheme)
        {
            // when user changes themes, close current theme and re-open
            ThemeHelper.CloseThemeData(m_hTheme);
            m_hTheme = NULL;
            m_bFirstTime = TRUE;
        }
    }
}

CXThemeHelper API

The CXThemeHelper API includes:
  • BOOL IsAppThemed()
  • BOOL IsThemeActive()
  • BOOL IsThemeLibAvailable()
  • BOOL CloseThemeData(HTHEME hTheme)
  • BOOL DrawThemeBackground()
  • BOOL DrawThemeParentBackground()
  • BOOL DrawThemeText()
  • BOOL GetThemeBackgroundContentRect()
  • HTHEME OpenThemeData()

Controlling XButtonXP Theming

CXButtonXP will use themes to draw button in the following circumstances:
  1. The app is running on XP
  2. Themes are enabled on system, and app has not been set to "Disable visual themes" via Properties dialog:
  3. screenshot

  4. Themes have not been disabled via CXButtonXP::EnableTheming() function.

CXButtonXP Starting Point

I used Ewan Ward's article Native Win32 Theme aware Owner-draw Controls without MFC as starting point for XButtonXP. First, I adapted his code for MFC, and then used CXThemeHelper to enable theme support. The next step was to fix default button problem.

Default Button Problem

This problem plagues all ownerdraw buttons. Left uncorrected, it can give the visual appearance that there are multiple default buttons on dialog, and improperly handles ENTER key. Fortunately, Paolo Messina describes this problem in detail, and has written very nice class to transparently fix this problem for any ownerdraw button.

Keyboard Input

The final task was to ensure that SPACE and ENTER keys worked properly. On standard pushbutton, these keys produce button-click event. In order for XButtonXP to handle them in same way, I had to intercept WM_GETDLGCODE message, and ask for all keys. At the same time, I did not want to interfere with TAB key processing. The WM_GETDLGCODE message provides mechanism to do this, by returning appropriate code. Then, I added handlers for WM_KEYDOWN and WM_KEYUP, to catch ENTER and SPACE key presses. I converted these to WM_LBUTTONDOWN and WM_LBUTTONUP messages, to emulate mouse click.

CXButtonXP Functions

Here are functions in CXButtonXP:

Function Description
CXButtonXP& EnableTheming(BOOL bEnable) Enable visual themes for button.
COLORREF GetBackgroundColor() Retrieve button custom background color (XBUTTONXP_NO_COLOR if none).
BOOL GetDrawToolbar() Get toolbar style (TRUE = use toolbar style).
COLORREF GetTextColor() Retrieve button custom text color (XBUTTONXP_NO_COLOR if none).
BOOL GetToggle() Get toggle style (TRUE = button acts like toggle).
BOOL GetToggleState() Get toggle state (TRUE = button is pressed).
BOOL IsThemed() Get theming state (TRUE = visual theme is being used).
CXButtonXP& SetBackgroundColor(COLORREF rgb = XBUTTONXP_NO_COLOR) Set button custom background color. Default is XBUTTONXP_NO_COLOR.
CXButtonXP& SetDrawToolbar(BOOL bDrawToolbar) Set toolbar style. Default is FALSE.
CXButtonXP& SetIcon(UINT nIDResource, ICON_ALIGNMENT ia = LEFT) Set icon from resource id.
CXButtonXP& SetIcon(HICON hIcon, ICON_ALIGNMENT ia = LEFT) Set icon from HICON.
CXButtonXP& SetIconAlignment(ICON_ALIGNMENT ia) Set icon alignment on button. Default is LEFT.
CXButtonXP& SetTextColor(COLORREF rgb = XBUTTONXP_NO_COLOR) Set button custom text color. Default is XBUTTONXP_NO_COLOR.
CXButtonXP& SetToggle(BOOL bIsToggle) Set toggle style. Default is FALSE.
CXButtonXP& SetToggleState(BOOL bToggled) Set toggle state. Default is FALSE.

How to use

To integrate CXButtonXP into your app, you first need to add following files to your project:

  • XButtonXP.cpp
  • XButtonXP.h
  • XThemeHelper.cpp
  • XThemeHelper.h
  • OddButton.cpp
  • OddButton.h
  • CreateGrayscaleIcon.h

Next, include header file XButtonXP.h in appropriate project files (typically the dialog header file). Now you are ready to start using CXButtonXP.

The demo app shows how to call XButtonXP:

    m_XButtonXP.SetIcon(IDI_MFC, CXButtonXP::LEFT);

You can combine XButtonXP function calls like this:

    m_XButtonXP.SetIcon(IDI_MFC, CXButtonXP::LEFT)
               .SetToggle(FALSE)
               .EnableTheming(TRUE)
               .SetDrawToolbar(FALSE);

screenshot

Tips & Tricks

  1. The button must not have BS_OWNERDRAW property in dialog template.
  2. When you include XButtonXP in your app, you might get error message about the symbol DFCS_HOT, even though you have installed Platform SDK. To fix this, you need to put this line in stdafx.h, before any includes:
    #define WINVER 0x0500
  3. The compiler error message fatal error C1083: Cannot open include file: 'uxtheme.h': No such file or directory means that compiler cannot find uxtheme.h, which is in Microsoft Platform SDK. This is free download from Microsoft site. I would give url here, but Microsoft keeps changing download page for Platform SDK, so best thing is to google for it.
  4. When custom colors are used for text or background, theming is automatically switched off.

Acknowledgments

Revision History

Version 1.3 - 2008 January 19

  • Fixed bug when button is released and mouse is moved, reported by rootdial.
  • Fixed problem with drawing as default button, reported by fredwobus and programbyran.
  • Fixed resource leak in DrawIcon(), reported by grin.
  • Fixed transparency bug for toolbar style, reported by Pandele Florin.
  • Fixed bug where WM_COMMAND was being sent twice when return pressed, reported by fredwobus.
  • Implemented WM_MOUSELEAVE handler, suggested by ksk, Roman Komary. fredwobus, 630596399 and EIEN.
  • Added multi-line support, requested by jlatorref.
  • Added grayscale support for disabled icon, requested by programbyran.
  • Added support for custom text and background colors, requested by PatLeCat and Alex Evans.
  • Added tooltips to demo.
  • Added option to display message box to demo.
  • Added option for hatch background to demo.
  • Added option for different icon color formats to demo.
  • Added option to select custom text and background colors to demo.

Version 1.2 - 2005 April 20

  • Fixed bug with hot state, reported by ksk
  • Added SetDrawToolbar() and GetDrawToolbar(), suggested by Dominik Reichl

Version 1.1 - 2005 March 30

  • Fixed bug in drawing toggle button, reported by Dominik Reichl.
  • Added SetToggleState()
  • Removed #include "XButtonXPTest.h" from XButtonXP.cpp

Version 1.0 - 2005 March 22

  • Initial public release

Usage

This software is released under The Code Project Open License (CPOL). You are free to use this software 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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Hans Dietrich
Software Developer (Senior) Hans Dietrich Software
United States United States
I attended St. Michael's College of the University of Toronto, with the intention of becoming a priest. A friend in the University's Computer Science Department got me interested in programming, and I have been hooked ever since.
 
Recently, I have moved to Los Angeles where I am doing consulting and development work.
 
For consulting and custom software development, please see www.hdsoft.org.






Comments and Discussions

 
Questionnice job, and not flickering! Pinmemberlanmanck8-Sep-13 16:20 
AnswerRe: nice job, and not flickering! Pinmemberlanmanck9-Feb-14 15:03 
AnswerRe: nice job, and not flickering! Pinmemberlanmanck8-May-14 16:08 
Questionhow to align center image and text on button? PingroupVCProgrammer6-Feb-13 23:09 
Questionthank you ^^ Pinmemberghajsk24-Apr-12 22:10 
Questionabout background Pinmemberhaisan11-Mar-12 3:37 
Questionwhy my edit controls is different with your? Pinmemberjiangxuqin3-Apr-11 5:30 
AnswerRe: why my edit controls is different with your? PinmentorHans Dietrich3-Apr-11 15:59 
GeneralRe: why my edit controls is different with your? Pinmemberjiangxuqin3-Apr-11 19:02 
GeneralRe: why my edit controls is different with your? Pinmemberjiangxuqin4-Apr-11 0:53 
GeneralAdding TOP and BOTTOM icon alignment Pinmemberabwd23-Sep-10 15:27 
GeneralRe: Adding TOP and BOTTOM icon alignment PinmemberJae-Hu Chae18-Feb-11 0:37 
AnswerRe: Adding TOP and BOTTOM icon alignment PinmentorHans Dietrich15-Apr-11 3:21 
QuestionHOW TO SET FONT FOR TEXT PinmemberMember 159084222-Aug-10 23:31 
AnswerRe: HOW TO SET FONT FOR TEXT PinmemberMember 159084223-Aug-10 16:59 
QuestionShow the question PinmemberMember 367654511-May-10 15:11 
When I execute the program, sometimes it could not show the button.Confused | :confused:
AnswerRe: Show the question PinmemberDeepBlueSpace3-Oct-10 22:35 
GeneralRe: Show the question PinmentorHans Dietrich4-Oct-10 18:55 
GeneralEdge drawing bug in XP PinmemberTsachi8-Jun-09 4:21 
GeneralRotated button Pinmemberli00005-Dec-08 2:50 
GeneralRe: Rotated button PinmvpHans Dietrich5-Dec-08 3:08 
GeneralRe: Rotated button Pinmemberli00005-Dec-08 10:50 
QuestionDrawThemeParentBackground() called improperly? PinmemberSkyhawk22-Aug-08 3:48 
GeneralXP Theme is not used if font colur is changed PinmemberAshutosh Bhawasinka15-Jul-08 20:29 
GeneralRe: XP Theme is not used if font colur is changed PinmvpHans Dietrich16-Jul-08 20:44 
GeneralRe: XP Theme is not used if font colur is changed Pinmemberchu-k-cha21-Nov-12 22:35 
GeneralThanks for xButtonXP Pinmemberxinhaijulan5-Jul-08 21:16 
GeneralAnother edge drawing problem PinmemberJohnnyfartpants19-May-08 22:57 
GeneralRe: Another edge drawing problem PinmemberJohnnyfartpants24-May-08 8:34 
GeneralMessagebox buttons PinmemberJohnnyfartpants18-May-08 23:37 
GeneralEdge around button Pinmemberfilippov.anton5-May-08 1:00 
GeneralRe: Edge around button PinmvpHans Dietrich5-May-08 5:04 
GeneralBitmap Loading PinmemberMember 18410913-May-08 22:45 
GeneralRe: Bitmap Loading PinmvpHans Dietrich4-May-08 1:33 
QuestionRe: Bitmap Loading PinmemberDavidCrow11-Apr-12 5:22 
GeneralWhy use toggle state instead of GetCheck/SetCheck PinmemberDon M8-Mar-08 7:11 
GeneralRe: Why use toggle state instead of GetCheck/SetCheck PinmemberDon M8-Mar-08 8:06 
QuestionHow to run the web browser in C++ Pinmemberreyd_todo19-Jan-08 10:25 
GeneralMouseMove while Button pressed Pinmemberrootdial17-Sep-07 23:29 
GeneralRe: MouseMove while Button pressed Pinmemberrootdial18-Sep-07 3:45 
QuestionDLL? PinmemberJohnny J.22-Apr-07 0:15 
QuestionHow to make a button "Selected" like XP "Add or Remove Programs" PinmemberSuper Garrison22-Aug-06 12:23 
AnswerRe: How to make a button "Selected" like XP "Add or Remove Programs" PinmemberJohnnyfartpants19-May-08 23:53 
GeneralMultiline Pinmemberjlatorref14-Dec-05 0:44 
GeneralAnother Approach PinmemberStephen C. Steel24-Nov-05 7:59 
QuestionCompile Error.... Pinmemberbakdorazi25-Sep-05 22:32 
AnswerRe: Compile Error.... Pinmember6305963998-Oct-05 9:10 
AnswerRe: Compile Error.... Pinmembercristitomi16-Mar-07 23:20 
GeneralDisabled icon drawn as in toolbar Pinmemberprogrambyran30-Jul-05 13:57 
GeneralDefault button gets no blue border Pinmemberprogrambyran30-Jul-05 12:56 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Flags: In ProgressCompletedUnable to replicateConfirmedAccepted

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140718.1 | Last Updated 19 Jan 2008
Article Copyright 2005 by Hans Dietrich
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid