一个简易的调色盘控件

© Conmajia 2012
Init. 18 July 2012
SN: 127.3

这是一个简单的 .NET 窗体控件,通过鼠标选择调色盘中给出颜色的 RGB 或十六进制值。

色块大小为 10 x 10 的调色盘控件在窗体中的应用

色块大小为 5 x 5 的调色盘控件在窗体中的应用

本控件的有效代码约 200 行,可以作为标准控件用于 .NET 框架的 WinForm 开发。

源代码:点击下载(78.8 KB)

此调色盘控件唯一功能是通过光标在调色盘上取色。光标在色块间移动时,通过 MouseMove 事件向主线程更新光标所在色块的颜色值,如 #0000FF 或 (0,0,255) 等。

调色盘由多个色块组成。演示代码中固定为 6 x 36 个色块,每个色块为 10 x 10 像素大小,占据窗体 60 x 360 像素区域。

色块大小为 10 x 10 的调色盘控件

如果增加色块数量而减小单个色块大小,如 60 x 360 个色块,每个色块为 1 x 1 像素,则此控件成为视觉连续的调色盘。

(仅供参考)色块大小为 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

猜你喜欢

转载自blog.csdn.net/conmajia/article/details/135252854