Introduction
When one comes to
editing color values, a variety of free custom
controls is
available on internet. Most of the time they are
color pickers, list boxes, property sheets with
system and HTML colors, etc. They usually work
with RGB components,
sometimes with the HSL
model. We felt that there was a lack with
edit-based color editors and we decided to mimic
one of the controls Jasc Software is using in
Paint Shop Pro to edit a color value,
component by
component in
the RGB (Red,
Green, Blue) and HSL
(Hue, Saturation, Light) models.
You can see a
screenshot of the well-known color dialog in PSP
at the top of this
article.
The goal is to
develop a control having the same behavior and the
exact same look. Why? Because we like this control
and we feel it as a standard that should come
naturally as an MFC
class. We understand that this piece of code is
not a revolution, but we are sure that some of you
will find it valuable for their own project.
So let's go and
first have a look at the object design of the
classes we show in this
article.
Design
Our
framework is
composed of four GUI
classes and two utility classes. As
usual for a custom control, we derive the main
class,
GWCColorComponentEditCtrl
(pretty long name), from
CWnd
.
Doing this will allow the client to integrate the
control in a
Cdialog
at design time (since we will also define a window
class) or dynamically in any window.
This main class is
linked to three internal
components:
- A
CEdit
instance: the user must be able to enter a value
directly at the keyboard.
- A
CspinButtonCtrl
instance: it's also convenient to modify a value
by clicking on these small arrows.
- A static window
called
GWCGradientColorWnd
:
this popup window makes easy to see the changes
on the color by dragging the mouse from the
minimum to the maximum value allowed (0 to 255).
Here is the
class
diagram
showing the links between all these elements :
As you can see
there is another class called
GWCColorComponentSet
.
This is one of the utility classes we talked
above. We created it for the following reason:
most of the time, you won't use
GWCColorComponentEditCtrl
alone. Instead you will create three of them to
edit the three components
of a color (either RGB or HSL). As you can see on
the PSP screenshot, they even show both models
with six controls.
GWCColorComponentSet
allows to link all these
components so that it keeps track of
the edited color and notifies the group when one
of them changes. It makes the client code and the
effort to produce to use this framework minimals.
The other utility
class,
GWCColorFunc
,
is a static class providing utility functions for
color conversions.
Note also the
bottom colored line below the edit control. This
is a convenient way to change the value with a
quick drag of the mouse. There is no underlying
window for this effect. Instead, the bar is drawn
by
GWCColorComponentEditCtrl
.
Installation
We have made the
code ready to be included as a library. Just unzip
the source package in a directory. Open the
workspace and compile all the desired
configurations (a mix of release/debug/lib/dll/Unicode).
All lib and dll files are produced in a
sub-directory called bin.
In
Visual C++
(tools -> options -> directories tab), add the bin
directory to your list of library directories and
its parent directory to the list of include
directories. Either the bin directory is in your
path or you copy the dlls in /windows/system32,
it's up to you.
The
source code is
fully commented so we won't go into it. Let's just
see how to use it in a dialog box. It's very
simple:
In your stdafx.h
file, add the following line:
You don't need to
insert a library file in your project because it
will be done automatically with this included
header file. However, you have to add a
preprocessor variable in your project settings in
the following cases:
- If you want to
use this control as a static library, define
_GWCCCECTRL_STATIC_
.
- If you want to
use this control as a DLL in one of your
MFC DLL,
define
_GWCCCECTRL_IN_OTHER_DLL
.
Of course, you
must have somewhere a
COLORREF
variable (m_myColor
)
in your code to hold your color.
Creation
Create a
GWCColorComponentSet
instance to hold the controls we will create:
GWCColorComponentSet m_compSet;
In the dialog
editor, create any number of custom controls you
want and set their window class to "ColorCompEditCtrl
".
Their height should be the same as a standard edit
control. Create the corresponding variables in the
dialog header file.
GWCColorComponentEditCtrl m_myComponent;
One more step for
the creation, in your dialog
DoDataExchange
method, add the following line for each of your
controls:
DDX_Control(pDX, IDC_MYCOMPONENT, m_myComponent);
When created
dynamically in a window instead of a dialog box,
use the following method:
Allocate all the
needed instances of
GWCColorComponentEditCtrl
and call their method Create. Use a height of 23
pixels for a standard look.
Initialization
Now you must
initialize each control and tell him what kind of
component it
represents. Basically, you do this in
OnInitDialog
:
m_myComponent.SetType(GWCColorComponentEditCtrl::RED);
Instead of
RED
you have the choice of
GREEN, BLUE, HUE, SAT, LIGHT
.
When you are done
with that, you link all your components in the
GWCColorComponentSet
instance and set the initial color.
m_compSet.RegisterComponentCtrl(m_myComponent);
m_compSet.SetColor(m_myColor);
Dynamics
Your window or
dialog box can be notified when one of the
components
changes. To do this you have to write a handler
for a registered message.
In the header file
add this in your message map:
afx_msg LRESULT OnColorCompChanged(WPARAM wParam, LPARAM lParam);
In the body add
this:
ON_REGISTERED_MESSAGE(WM_GWCCOLORCOMPEDIT_CHANGED, OnColorCompChanged)
LRESULT CMyDialog::OnColorCompChanged(WPARAM wParam, LPARAM lParam)
{
m_myColor = m_compSet.GetColor();
return (LRESULT)0;
}
wParam
contains the value of the component (0 to 255) and
lParam
contains the window identifier of the control that
sent this message.
Disclaimer
This software,
source code
and sample, is
provided "as is". Aircom software makes no
representations or warranties of any kind
concerning the quality, safety or suitability of
the software, either expressed or implied,
including without limitation any implied
warranties of merchantability, fitness for a
particular purpose, or non-infringement.