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:
- Modified for use with WTL.
- Update style to more closely resemble the Office XP color picker.
- Optional support for XP themes.
- Control uses
WM_NOTIFY
instead of WM_COMMAND
.
- Finally got rid of that damn annoying dialog bar focus problem by
using a captive message loop to process the picker.
- 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.
- The first step is to copy CColorButton.h and CColorButton.cpp into
you application directory.
- Next, add the two files into your project.
- 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.
- 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.
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.
- Add a button to the dialog in question using the resource
editor. You don't have to make and style adjustments to the
button.
- Edit the class definition for the dialog box. To the message map,
add "
REFLECT_NOTIFICATIONS ()
".
- Add "#include "ColorButton.h"" prior to the
definition of the dialog box class.
- Add a new member variable to the dialog. The class will be "CColorButton"
and give it any name you desire.
- 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 , WPARAM ,
LPARAM , BOOL& )
{
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
COLORREF GetColor (void) const;
void SetColor (COLORREF clrCurrent);
COLORREF GetDefaultColor (void) const;
void SetDefaultColor (COLORREF clrDefault);
void SetCustomText (LPCTSTR pszText);
void SetCustomText (UINT nID);
void SetDefaultText (LPCTSTR pszText);
void SetDefaultText (UINT nID);
BOOL GetTrackSelection (void) const;
void SetTrackSelection (BOOL fTrack);
void SetText (UINT nDefault, UINT nCustom);
BOOL HasCustomText () const;
BOOL HasDefaultText () const;
Handling Notifications
Notifications are sent using the standard WM_NOTIFY message.
#define CPN_SELCHANGE 0x8000
#define CPN_DROPDOWN 0x8001
#define CPN_CLOSEUP 0x8002
#define CPN_SELENDOK 0x8003
#define CPN_SELENDCANCEL 0x8004
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.