65.9K
CodeProject 正在变化。 阅读更多。
Home

创建颜色选择面板控件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.25/5 (8投票s)

2005年1月3日

3分钟阅读

viewsIcon

67023

downloadIcon

1031

创建一个用户控件,用于使用调色板选择前景和背景颜色。

Sample Image - ColorPaletteControl.jpg

引言

我创建颜色选择控件的第一次尝试(ColorMap 控件)实际上有两个主要的缺点。首先:灰色在哪里?这是我收到的第一个评论。老实说,在 ColorMap 中不容易找到灰色。哦,它们就在那里。如果您计算红色值等于绿色值等于蓝色值的颜色数量(根据定义,这是一个灰色值),您会发现大约有 400 个灰色值。但这只是理论,你仍然无法选择它们!

这就引出了第二个主要缺点。我在 ColorMap 文章中已经解释过。选择一种颜色效果很好,再次选择完全相同的颜色就像一项不可能完成的任务。

所以我们真正需要的是一个颜色调色板。不是数千种颜色,而是一些固定数量的独特颜色,这样我们就可以轻松地记住我们昨天选择了哪种颜色。但是,我们必须确保所有颜色类型都可用。哦,这次我们想看到灰色!

创建控件

在实际创建控件之前,让我们总结一下控件的功能

  • 显示一个包含所有颜色类型和灰色的调色板。
  • 通过在颜色映射上的任何位置单击左键来设置前景颜色属性。
  • 通过在颜色映射上的任何位置单击右键来设置背景颜色属性。

由于我们有调色板,我们添加了另外两个要求

  • 设置每列显示的颜色数量。
  • 设置显示单个颜色的区域的大小。

ColorMap 控件是一个很好的起点。它包含了列出的大部分功能。新的是 ColorsPerColumnColorSize 值。此外,ColorMap 控件的 CreateColorMap 方法被重命名为 CreateColorPalette。与 ColorMap 控件一样,该方法返回一个位图。

颜色调色板

颜色调色板只不过是一个以彩色方块形式显示的颜色列表。每个彩色方块的大小为 ColorSize。因此,问题在于创建要显示的颜色列表并以有意义的方式对它们进行排序。

第一个问题并不难解决。我们可以编写一些逻辑来创建一个颜色列表,但是 .NET Color 类包含我们想看到的所有颜色。获取这些颜色是使用反射来检查 Color 类并提取静态颜色属性的问题。以下是操作方法。

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);
}

如果显示此颜色列表,您会发现它们是随机散布的。这是因为这些颜色按名称按字母顺序排序。

我们需要一种对颜色进行排序的好方法。一种排序方法是使用 RGB 值。同样,这将创建一个对人眼来说似乎是随机的颜色顺序。幸运的是,除了 RGB 排序之外,还有另一种选择。它被称为色调-饱和度-亮度(或 HSB)。色调值确定颜色在色轮中的位置。对于那些不知道什么是色轮的人,它看起来是这样的

Sample image

饱和度值决定了颜色中的灰色程度。亮度值决定了颜色的强度。

排序算法首先按色调排序,然后按饱和度排序,最后按亮度排序。该逻辑被捕获在实现 IComparer 接口的内部类 _ColorSorter 中。请注意,排序与 Visual Studio 属性窗口中颜色的排序相同。

/// <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
}

关注点

显示的颜色列表包含我称之为“白色间隙”的东西。起初,我将其视为排序问题,直到我仔细观察 Visual Studio 属性窗口中显示的颜色,发现这里也显示了相同的“白色间隙”。

看到一种算法,该算法生成一个颜色列表,当按色调-饱和度-亮度排序时,不会在调色板中创建白色间隙,将会很有趣。

历史

  • 2004-12-21 - 文章的初始版本。
© . All rights reserved.