创建颜色选择面板控件






4.25/5 (8投票s)
2005年1月3日
3分钟阅读

67023

1031
创建一个用户控件,用于使用调色板选择前景和背景颜色。
引言
我创建颜色选择控件的第一次尝试(ColorMap
控件)实际上有两个主要的缺点。首先:灰色在哪里?这是我收到的第一个评论。老实说,在 ColorMap
中不容易找到灰色。哦,它们就在那里。如果您计算红色值等于绿色值等于蓝色值的颜色数量(根据定义,这是一个灰色值),您会发现大约有 400 个灰色值。但这只是理论,你仍然无法选择它们!
这就引出了第二个主要缺点。我在 ColorMap
文章中已经解释过。选择一种颜色效果很好,再次选择完全相同的颜色就像一项不可能完成的任务。
所以我们真正需要的是一个颜色调色板。不是数千种颜色,而是一些固定数量的独特颜色,这样我们就可以轻松地记住我们昨天选择了哪种颜色。但是,我们必须确保所有颜色类型都可用。哦,这次我们想看到灰色!
创建控件
在实际创建控件之前,让我们总结一下控件的功能
- 显示一个包含所有颜色类型和灰色的调色板。
- 通过在颜色映射上的任何位置单击左键来设置前景颜色属性。
- 通过在颜色映射上的任何位置单击右键来设置背景颜色属性。
由于我们有调色板,我们添加了另外两个要求
- 设置每列显示的颜色数量。
- 设置显示单个颜色的区域的大小。
ColorMap
控件是一个很好的起点。它包含了列出的大部分功能。新的是 ColorsPerColumn
和 ColorSize
值。此外,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)。色调值确定颜色在色轮中的位置。对于那些不知道什么是色轮的人,它看起来是这样的
饱和度值决定了颜色中的灰色程度。亮度值决定了颜色的强度。
排序算法首先按色调排序,然后按饱和度排序,最后按亮度排序。该逻辑被捕获在实现 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 - 文章的初始版本。