Click here to Skip to main content
15,867,488 members
Articles / Desktop Programming / Windows Forms
Article

Creating a color selection palette control

Rate me:
Please Sign up or sign in to vote.
4.25/5 (8 votes)
2 Jan 20053 min read 65.9K   1K   24   1
Creating a user control for selecting a foreground and background color using a palette.

Sample Image - ColorPaletteControl.jpg

Introduction

My first attempt to create a color selection control (the ColorMap control) actually had two major drawbacks. First: where are the grays? This was the first remark I got. And to be honest with you, grays are not easily found in the ColorMap. Oh, they're there. If you count the number of colors with red-value equals green-value equals blue-value (by definition a gray value), you'll find approximately 400 values of grays. But that's theory and you still can't select them!

That brings me to the second major drawback. One I already explained in the ColorMap article. Selecting a color works fine, selecting the exact same color again is like a mission impossible.

So what we actually need is a palette of colors. Not thousands of colors, but rather a fixed number of distinct colors, so that we easily can remember which color it was we selected yesterday. However, we have to make sure all color types are available. Oh, and this time we want to see grays!

Creating the control

Before actually creating the control, let's summarize the functionality of the control:

  • display a palette of colors containing all types of colors and grays.
  • set the foreground color property by left clicking anywhere on the color map.
  • set the background color property by right clicking anywhere on the color map.

And since we have palette, we add two more requirements:

  • set the number of colors displayed per column.
  • set the size of area displaying a single color.

The ColorMap control is a good place to start. It contains most of the functionality listed. New are the values ColorsPerColumn and ColorSize. Also, the CreateColorMap method of the ColorMap control is renamed to CreateColorPalette. As in the ColorMap control, the method returns a bitmap.

The color palette

The color palette is nothing more than a list of colors displayed as colored squares. Each colored square being of size ColorSize. So, the problem is creating the list of colors to be displayed and have them ordered in a way that makes sense.

The first problem was not that hard to solve. We could write some logic to create a list of colors, but the .NET Color class contains all the colors we want to see. Getting these colors is a matter of using reflection to inspect the Color class and extract the static color properties. Here's how to do it.

C#
PropertyInfo[]   properties;
ArrayList        colors;
Color            color;
SolidBrush       brush;

// get all colors defined as properties in the Color class
properties = 
    typeof (Color).GetProperties (BindingFlags.Public | BindingFlags.Static);
colors = new ArrayList ();
foreach (PropertyInfo prop in properties) {
    // get the value of this static property
    color = (Color) prop.GetValue (null, null);
    // skip colors that are not interesting
    if (color == Color.Transparent) continue;
    if (color == Color.Empty) continue;    
    // create a solid brush of this color
    brush = new SolidBrush (color);
    colors.Add (brush);
}

If you display this list of colors, you'll find that they're randomly scattered. That's because the colors are ordered alphabetically by name.

What we need is a good way to sort the colors. One method of ordering is using the RGB-value. Again, this will create an order in the colors that seems random to the human eye. Luckily, there is an alternative to RGB-ordering. It is called hue-saturation-brightness (or HSB). The value hue determines the location of the color in the color circle. For those of you who don't know what a color circle is, here's how it looks like:

Sample image

The saturation value determines how much grey is in the color. The brightness value determines the color's intensity.

The sorting algorithm first orders by hue, then by saturation, and finally by brightness. The logic is captured in the internal class _ColorSorter which implements the IComparer interface. Note that the sorting is identical to the sorting of colors in the property window in Visual Studio.

C#
/// <SUMMARY>
/// The class _ColorSorter orders the colors based on the hue,
/// saturation and brightness. This is the
/// order that is also used by visual studio.
/// </SUMMARY>
internal class _ColorSorter: System.Collections.IComparer {

    #region IComparer Members

    public int Compare (object x, object y) {
        // local variables
        Color                    cx, cy;
        float                    hx, hy, sx, sy, bx, by;

        // get Color values
        cx = ((SolidBrush) x).Color;
        cy = ((SolidBrush) y).Color;
        // get saturation values
        sx = cx.GetSaturation ();
        sy = cy.GetSaturation ();
        // get hue values
        hx = cx.GetHue ();
        hy = cy.GetHue ();
        // get brightness values
        bx = cx.GetBrightness ();
        by = cy.GetBrightness ();

        // determine order
        // 1 : hue       
        if (hx < hy) return -1; 
        else if (hx > hy) return 1;
        else {
            // 2 : saturation
            if (sx < sy) return -1;
            else if (sx > sy) return 1;
            else {
                // 3 : brightness
                if (bx < by) return -1;
                else if (bx > by) return 1;
                else return 0;
            }
        }
    }

    #endregion
}

Points of Interest

The list of colors displayed contains what I call 'white gaps'. At first, I considered this to be a sorting problem, that is, until I took a good look at the colors shown in the Visual Studio property window and found that the same 'white gaps' were shown here also.

It would be interesting to see an algorithm that generates a list of colors that, when sorted by hue-saturation-brightness, doesn't create white gaps in the palette.

History

  • 2004-12-21 - Initial release of article.

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
Netherlands Netherlands
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralThis sort crashes in release mode. [modified] Pin
metalmonkey13-Nov-07 15:09
metalmonkey13-Nov-07 15:09 
I tried in 'Debug' everything is ok.
In release the application locks up entirely (with no exception)
Eventually I got the app to throw an exception.

"IComparer ... did not return zero when Array.Sort called x.CompareTo(x). x: 'Color [LightPink]'"


I never really liked 'LightPink' anyway.

I fixed the problem by adding:

public int Compare (object x, object y)
{
// local variables
Color cx, cy;

if (cx.Equals(cy))
return 0;

.
.
.
}


-- modified at 23:34 Tuesday 13th November, 2007

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.