Click here to Skip to main content
15,861,125 members
Articles / Desktop Programming / WTL
Article

Color Picker for WTL with XP themes

Rate me:
Please Sign up or sign in to vote.
5.00/5 (22 votes)
13 Jun 20025 min read 188.5K   4.3K   47   30
Color picker control for WTL applications including optional support for XP themes

Sample Image - wtlcolorbutton.jpg

Introduction

Using the Color Picker Button by James White who in turn based his work on Office 97 Colour Picker Control by Chris Maunder, I have created an updated color picker control based on the Office XP designed intended for use with WTL.

Among the list of changes are:

  1. Modified for use with WTL.
  2. Update style to more closely resemble the Office XP color picker.
  3. Optional support for XP themes.
  4. Control uses WM_NOTIFY instead of WM_COMMAND.
  5. Finally got rid of that damn annoying dialog bar focus problem by using a captive message loop to process the picker.
  6. The code is really phat now.  I mean really phat.

NOTE: VS.NET/ATL7/WTL7 are required to get the full functionality of this control.  It is untested with ATL3/WTL3 but since the theme support if optional, there is a good chance it could work.

Adding CColorButton to a WTL application.

  1. The first step is to copy CColorButton.h and CColorButton.cpp into you application directory.
  2. Next, add the two files into your project.
  3. Many little features will not be enabled unless you have WINVER and _WIN32_WINNT defined properly. You can defined these values in your stdafx.h. 
  4. If you want XP theme support, add "#include <atltheme.h>" to your stdafx.h file. This should be placed after all the other ATL includes.
  5. CColorButton makes heavy use of helper types from ATL. You will need to make sure that "atltypes.h" and "atlgdi.h" are being included in stdafx.h.
  6. Add a button to the dialog in question using the resource editor.  You don't have to make and style adjustments to the button.
  7. Edit the class definition for the dialog box. To the message map, add "REFLECT_NOTIFICATIONS ()".
  8. Add "#include "ColorButton.h"" prior to the definition of the dialog box class.
  9. Add a new member variable to the dialog. The class will be "CColorButton" and give it any name you desire. 
  10. Inside your OnInitDialog for the dialog, add a line to subclass the control. It is important that is it subclassed and not just assigned a window handle.

Here is an example of how to properly subclass the control.

LRESULT CMainDlg::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, 
                               LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	// center the dialog on the screen
	CenterWindow();

	m_btnMyColor1 .SubclassWindow (GetDlgItem (IDC_COLOR_1));
	m_btnMyColor2 .SubclassWindow (GetDlgItem (IDC_COLOR_2));
	m_btnMyColor3 .SubclassWindow (GetDlgItem (IDC_COLOR_3));

	m_btnMyColor2 .SetDefaultText (_T (""));
	m_btnMyColor2 .SetCustomText (_T (""));
	m_btnMyColor3 .SetDefaultText (_T ("My Default Text"));
	m_btnMyColor3 .SetCustomText (_T (""));
	return TRUE;
}

Here is a list of the different features enabled by defines.

Define Value Features Enabled
_WIN32_WINNT 0x0501 Theme support
XP flat menu support
XP drop shadow support
WINVER 0x0500 Multi-monitor support
XP menu highlight color support
WINVER 0x0501 XP menu highlight color support

For most applications, both _WIN32_WINNT and WINVER should be defined to be 0x0501.  The CColorButton control will automatically downgrade if the operating system doesn't provide the functionality enabled by _WIN32_WINNT and WINVER.

How the Color Picker handles Colors

The color picker supports three types of colors, default, custom and palette.  The palette colors are the colors shown to the user as an array of little tiles of color.  The default color is shown to the user as a large button on the top of the picker with text supplied by the application.  The default for this text is "Automatic".  The custom color is shown to the user as a large button on the bottom of the picker with text supplied by the application.  The default for this text is "Custom...".

The nice thing about the way Chris originally implemented the color picker is that 99% of this is totally transparent to the application developer.  When the application interacts with the color picker, all it needs to be concerned about is the currently selected color.  This color is a standard COLORREF and can be easily set using the RGB (red, green, blue) macro.  When an application needs to set the color picker to a specific value, just pass the COLORREF value into the SetColor method.  When it needs to retrieve the current color, just invoke the GetColor method.  

Well, except for handling the default color.

Working With the Default Color

The default color is handled using a special COLORREF value of CLR_DEFAULT.  When this value is passed to the SetColor method, the color button recognizes it as a specialized value.  When the actual picker is displayed, the default selection will be highlighted.  However, when the default color is set, the color button must know what color to display in the button. This color can be set by using the SetDefaultColor method.  If this value isn't set, then the color button will display the default color for application workspace backgrounds.

When the user selects the default color in the color picker, the GetColor method will return CLR_DEFAULT. This allows the application to tell the difference between the default color being selected and a color from the palette being selected that matches in

RGB
value to the actual default color.

Working With the Custom Colors

Custom colors are totally transparent to the application developer.  No special programming is needed.

The CColorButton public member functions

// Return the currently selected color

COLORREF GetColor (void) const;

// Set the current color

void SetColor (COLORREF clrCurrent);

// Get the default color

COLORREF GetDefaultColor (void) const;

// Set the default color.  This value should be a real color value
// and not CLR_DEFAULT.

void SetDefaultColor (COLORREF clrDefault);

// Set the custom text.  Specify _T ("") to disable the custom 
// text button.

void SetCustomText (LPCTSTR pszText);

// Set the custom text via a resource string.  Specify a 0 to
// disable the custom text button.

void SetCustomText (UINT nID);

// Set the default text.  Specify _T ("") to disable the default 
// text button.

void SetDefaultText (LPCTSTR pszText);

// Set the default text via a resource string.  Specify a 0 to
// disable the default text buttom.

void SetDefaultText (UINT nID);

// Get the tracking flag

BOOL GetTrackSelection (void) const;

// Set the tracking flag.  When enabled, the application will be
// sent color change notifications as the user tracks around the
// picker.

void SetTrackSelection (BOOL fTrack);

// Set both strings from a resource

void SetText (UINT nDefault, UINT nCustom);

// Do we have custom text

BOOL HasCustomText () const;

// Do we have default text

BOOL HasDefaultText () const;

Handling Notifications

Notifications are sent using the standard WM_NOTIFY message.  

#define CPN_SELCHANGE        0x8000	/* Colour Picker Selection change */
#define CPN_DROPDOWN         0x8001	/* Colour Picker drop down */
#define CPN_CLOSEUP          0x8002	/* Colour Picker close up */
#define CPN_SELENDOK         0x8003	/* Colour Picker end OK */
#define CPN_SELENDCANCEL     0x8004	/* Colour Picker end (cancelled) */

struct NMCOLORBUTTON
{
	NMHDR	hdr;
	BOOL	fColorValid;
	COLORREF	clr;
};

CPN_SELCHANGE is sent to the parent window after the user changes the current selection.  It is also sent as the user tracks over different buttons in the picker window.  If the user cancels the picker while tracking, CPN_SELCHANGE will be sent to the parent window when the color is restored back to the selected color prior to the picker being displayed.  When CPN_SELCHANGE is sent as part of tracking, the fColorValid element of the notification structure is set to true if the user is tracking over a valid color selection.  When false, the user has moved the mouse outside of the picker window.

CPN_DROPDOWN is sent to the parent window prior to the picker window being displayed.

CPN_CLOSEUP is sent to the parent window after the picker window has been closed.

CPN_SELENDOK is sent to the parent window after the picker window has been closed with a valid selection and not canceled.

CPN_SELENDCANCEL is sent to the parent window after the picker window has been closed but canceled by the user.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Canada Canada
Tim has been a professional programmer for way too long. He currently works in the tools department at BioWare Corp..

Comments and Discussions

 
QuestionAppearance bug Pin
Nikolay Ananenko7-Mar-12 3:13
Nikolay Ananenko7-Mar-12 3:13 
GeneralCannot compile in a WTL8.1 project Pin
Member 381982114-Jun-10 0:34
Member 381982114-Jun-10 0:34 
GeneralRe: Cannot compile in a WTL8.1 project Pin
Edwall Karl10-Nov-10 16:53
Edwall Karl10-Nov-10 16:53 
GeneralNot friendly to ComboBox Pin
JJ@BC18-Apr-05 14:42
JJ@BC18-Apr-05 14:42 
GeneralLooks very good Pin
Kefirius12-Nov-04 11:23
Kefirius12-Nov-04 11:23 
GeneralGreate and one question Pin
bektek31-Oct-04 21:52
bektek31-Oct-04 21:52 
GeneralRe: Greate and one question Pin
Tim Smith1-Nov-04 3:05
Tim Smith1-Nov-04 3:05 
GeneralRe: Greate and one question Pin
bektek1-Nov-04 5:50
bektek1-Nov-04 5:50 
GeneralGreat! And a suggestion Pin
Michael Dunn3-Sep-04 16:49
sitebuilderMichael Dunn3-Sep-04 16:49 
QuestionColorPicker within ATL DLL? Pin
balbi2110-Aug-04 7:54
balbi2110-Aug-04 7:54 
AnswerRe: ColorPicker within ATL DLL? Pin
Tim Smith10-Aug-04 15:08
Tim Smith10-Aug-04 15:08 
GeneralQuestion Pin
Jörgen Sigvardsson3-Aug-04 3:58
Jörgen Sigvardsson3-Aug-04 3:58 
GeneralRe: Question Pin
Tim Smith3-Aug-04 4:21
Tim Smith3-Aug-04 4:21 
GeneralSweet! Pin
Jörgen Sigvardsson3-Aug-04 0:53
Jörgen Sigvardsson3-Aug-04 0:53 
GeneralRe: Sweet! Pin
Tim Smith3-Aug-04 4:22
Tim Smith3-Aug-04 4:22 
GeneralHook to toolbar button Pin
peter@howudodat.com13-May-04 5:43
peter@howudodat.com13-May-04 5:43 
GeneralRe: Hook to toolbar button Pin
Tim Smith13-May-04 8:41
Tim Smith13-May-04 8:41 
QuestionCan I open this project with VC++ v6? Pin
Angus Comber13-May-03 6:40
Angus Comber13-May-03 6:40 
AnswerRe: Can I open this project with VC++ v6? Pin
Tim Smith13-May-03 7:24
Tim Smith13-May-03 7:24 
AnswerRe: Can I open this project with VC++ v6? Pin
Anonymous8-Oct-05 4:12
Anonymous8-Oct-05 4:12 
GeneralDoesn't work on non-XP systems (fix provded) Pin
Nebula__2-May-03 11:50
Nebula__2-May-03 11:50 
GeneralRe: Nope, not a problem, no fix required Pin
Tim Smith2-May-03 12:42
Tim Smith2-May-03 12:42 
GeneralRe: Nope, not a problem, no fix required Pin
Nebula__2-May-03 12:57
Nebula__2-May-03 12:57 
GeneralOkay :-) It was the demo app exe or something Pin
Nebula__2-May-03 13:09
Nebula__2-May-03 13:09 
GeneralRe: Nope, not a problem, no fix required Pin
Tim Smith3-May-03 1:56
Tim Smith3-May-03 1:56 

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

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