? Conmajia 2012
Init. 18 July 2012
SN: 127.3
这是一个简单的 .NET 窗体控件,通过鼠标选择调色盘中给出颜色的 RGB 或十六进制值。
本控件的有效代码约 200 行,可以作为标准控件用于 .NET 框架的 WinForm 开发。
源代码:点击下载(78.8 KB)
此调色盘控件唯一功能是通过光标在调色盘上取色。光标在色块间移动时,通过 MouseMove
事件向主线程更新光标所在色块的颜色值,如 #0000FF 或 (0,0,255) 等。
调色盘由多个色块组成。演示代码中固定为 6 x 36 个色块,每个色块为 10 x 10 像素大小,占据窗体 60 x 360 像素区域。
如果增加色块数量而减小单个色块大小,如 60 x 360 个色块,每个色块为 1 x 1 像素,则此控件成为视觉连续的调色盘。
编码实现
控件直接由 GDI+ 绘制而成,图层分布如下。
图层内容 | 绘图层(1:最低,5:最高) |
---|---|
光标示宽器 | 5 |
调色盘边框 | 4 |
色块网格 | 3 |
色块 | 2 |
背景 | 1 |
protected override void OnPaint(PaintEventArgs e) {
Graphics g = e.Graphics;
drawPalette(g);
drawGrid(g);
drawBorder(g);
drawCursor(g);
}
各层的绘制代码相当简单,演示如下。
drawPalette
void drawPalette(Graphics g) {
SolidBrush b = (SolidBrush) brush;
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
b.Color = getColor(row, col);
g.FillRectangle(
b,
blockWidth * col, blockWidth * row,
blockWidth, blockWidth
);
}
}
}
drawGrid
void drawGrid(Graphics g) {
for (int i = 0; i < rows; i++) {
g.DrawLine(
Pens.Black,
0, blockWidth * (i + 1),
blockWidth * cols, blockWidth * (i + 1)
);
}
for (int i = 0; i < cols; i++) {
g.DrawLine(
Pens.Black,
blockWidth * (i + 1), 0,
blockWidth * (i + 1), blockWidth * rows
);
}
}
drawBorder
void drawBorder(Graphics g) {
g.DrawRectangle(
Pens.Black,
0, 0,
blockWidth * cols, blockWidth * rows
);
}
drawCursor
void drawCursor(Graphics g) {
g.DrawRectangle(
Pens.White,
cursor
);
}
获取颜色可以结合光标位置基于绘制调色盘时的算法确定。更简单一点,直接读取光标所在点的位图像素值,如下。
Color getColor(int row, int col) {
byte r = 0, g = 0, b = 0;
int step = 0xff / (rows - 1);
r = (byte)(row * step);
g = (byte)(step * (col / rows));
b = (byte)(step * (col % rows));
return Color.FromArgb(r, g, b);
}
光标的移动处理可以用
current = getColor(pt.Y / blockWidth, pt.X / blockWidth);
得到。鼠标移动时会绘制光标,不建议也不需要重绘整个控件。为了减少性能开销,使用 Invalidate(Rectangle)
来重绘被鼠标弄脏的那个区域。用两个小矩形保存旧光标和新光标的区域,然后在鼠标事件中更新。
void updateCursor(Point pt) {
lastCursor.X = cursor.X;
lastCursor.Y = cursor.Y;
cursor.X = pt.X - pt.X % blockWidth;
cursor.Y = pt.Y - pt.Y % blockWidth;
current = getColor(pt.Y / blockWidth, pt.X / blockWidth);
}
重绘时稍稍扩大点重绘区域可以得到更棒的表现。
protected override void OnMouseMove(MouseEventArgs e) {
updateCursor(e.Location);
Invalidate(new Rectangle(
lastCursor.X - 1, lastCursor.Y - 1,
lastCursor.Width + 2, lastCursor.Height + 2));
Invalidate(new Rectangle(
cursor.X - 1, cursor.Y - 1,
cursor.Width + 2, cursor.Height + 2));
OnColorChanged();
}
添加自定义的 ColorChanged
事件处理,最后将全部代码封装为合规的窗体控件即告完成。
public delegate void ColorChangedEventHandler(object sender, ColorChangedEventArgs e);
[Description("Fires every time when color changed.")]
public event ColorChangedEventHandler ColorChanged;
protected virtual void OnColorChanged() {
if (ColorChanged != null) ColorChanged(this, new ColorChangedEventArgs(current));
}
public class ColorChangedEventArgs: EventArgs {
Color color = Color.Black;
public Color Color {
get { return color; }
set { color = value; }
}
public ColorChangedEventArgs(Color color): base() {
this.color = color;
}
}
? Conmajia 2012