「玩一玩」一个简单的调色板取色器控件

Conmajia 2012-07-18 04:53:37
加精
看书让我感觉很犯困。。果然不是外行干的事。。

于是做了个这个提提神。。


控件按我的习惯写出来刚好256行代码。。去掉各种废话也就200行左右。。

==========

很简单,本来打算做一个可以自适应任何尺寸的,实在懒得想了。
高手请自动飘过。需要练习自绘控件的朋友可以瞄几眼看看,难度不高,用来练手正好。

难度:★★☆☆☆

源码:点击下载

控件看起来是这样的。

功能:
取色,取到的颜色可以通过ColorChanged事件参数e.Color获得,还可以在控件里把current变量公开出来(我没公开)
设置色块大小,3-20,这会影响控件的整体尺寸:
Block size 5

Block size 10

Block size 15


控件由很多色块组成。目前固定尺寸6x36,你可以自己修改尺寸。
控件分层是这样的(从最底层到最上层):
1.控件绘图面
2.色块
3.网格
4.边框
5.光标

在Paint事件中按上面顺序绘制2-5。
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
drawPalette(g);
drawGrid(g);
drawBorder(g);
drawCursor(g);
}

绘制网格很简单,根据色块大小隔一定距离画一道横(竖)线
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
);
}
}

绘制色块道理差不多,先获取当前坐标(行,列)的颜色(根据你自己定义的调色盘计算出来),然后填充一个方块,转到处理下一个坐标,直到全部行列都处理完。
这是我的获取颜色算法
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);
}

然后绘制所有色块,代码很简单,就不贴了。

从表面上看,是通过鼠标移动,选取每个色块获得颜色。其实不然。那样做,我就需要保存每个色块的颜色信息,白白浪费空间。我的实现方法是通过鼠标位置得知当前鼠标所在色块的坐标(行,列),然后用上面的颜色算法直接得到该色块的颜色,一句话搞定(Point pt是鼠标位置)。
current = getColor(pt.Y / blockWidth, pt.X / blockWidth);


鼠标移动时会绘制光标,为了减少性能开销,不能直接Refresh()/Invalidate()控件,使用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);

// redraw larger spaces
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
)
);

// fire event
OnColorChanged();
}


最后一行「OnColorChanged();」是用来引发颜色改变事件。把事件写出来基本就完成了。
// -- custom events
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));
}

// custom event args
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;
}
}


然后再完善下属性之类的,就可以在你的程序里使用了。
...全文
2314 98 打赏 收藏 转发到动态 举报
写回复
用AI写文章
98 条回复
切换为时间正序
请发表友善的回复…
发表回复
gao117348222 2012-08-03
  • 打赏
  • 举报
回复
我觉得可以用label来代替颜色小块,然后在点击事件中取得这个label的颜色信息。
fyhxiazai 2012-08-03
  • 打赏
  • 举报
回复
hao dong dong!
lookm 2012-08-03
  • 打赏
  • 举报
回复
欣赏的态度看强人
lxs0710 2012-07-27
  • 打赏
  • 举报
回复
好专业
lxs0710 2012-07-27
  • 打赏
  • 举报
回复
好专业
leilijuan0820 2012-07-27
  • 打赏
  • 举报
回复
刚开始学C#! 好讨厌调试啊! 错误怎么那么多?
l498229230 2012-07-26
  • 打赏
  • 举报
回复
不错,
很多图像存储格式都是这种方式:
1、存储每个像素在颜色面板的索引
2、存储颜色面板

haomei2 2012-07-25
  • 打赏
  • 举报
回复
从.net framework的所设计应用场景 String.Concat的重载方法,方法参数是(param object[]),你可以传入int,string,point,等值类型和引用类型,当你传入值类型变量,就会发生装箱的操作。再比如说方法调用声明一个Int类型的变量i,i调用父类方法GetType,因为i为值类型,想要调用父类方法就必须装箱,然后通过装箱后的对象来查找上级类型对象指针,查找方法表中所调用的方法,传入this实参,这也是装箱的应用场景

kbcslang 2012-07-25
  • 打赏
  • 举报
回复
路过,欣赏的态度看强人
Mydwr 2012-07-25
  • 打赏
  • 举报
回复
围观,不错!牛人
Summerza 2012-07-25
  • 打赏
  • 举报
回复
不错,
很多图像存储格式都是这种方式:
1、存储每个像素在颜色面板的索引
2、存储颜色面板

相当于仿射变换。
qxyywy 2012-07-25
  • 打赏
  • 举报
回复
[Quote=引用 71 楼 的回复:]

用PS画个全色图,代码只需要一句
...getpixel(x,y)
[/Quote]
这个一定要MARK下 平时也想的是自己去构造N多颜色然后来取
xiaoshahai 2012-07-25
  • 打赏
  • 举报
回复
好东西,学习了
oFuShengRuoMeng 2012-07-25
  • 打赏
  • 举报
回复
用PS画个全色图,代码只需要一句
...getpixel(x,y) 支持一下
oFuShengRuoMeng 2012-07-25
  • 打赏
  • 举报
回复
很好 写的不错 支持一下
Conmajia 2012-07-23
  • 打赏
  • 举报
回复
[Quote=引用 71 楼 的回复:]

用PS画个全色图,代码只需要一句
...getpixel(x,y)
[/Quote]各种方法都行,根据实际需要。。
dylike 2012-07-23
  • 打赏
  • 举报
回复
用PS画个全色图,代码只需要一句
...getpixel(x,y)
子牙河畔 2012-07-23
  • 打赏
  • 举报
回复
俺也想学c#
a490740700 2012-07-19
  • 打赏
  • 举报
回复
不错,
很多图像存储格式都是这种方式:
1、存储每个像素在颜色面板的索引
2、存储颜色面板

相当于仿射变换。
Conmajia 2012-07-18
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 的回复:]

最近也在看这本书,已经看了120多页了
[/Quote]
我才看25页。。还有尼玛800多页。。
加载更多回复(4)
功能介绍: 取色,取到的颜色可以通过ColorChanged事件参数e.Color获得,还可以在控件里把current变量公开出来 实现过程: 控件由很多色块组成。目前固定尺寸6x36,你可以自己修改尺寸。 控件分层是这样的(从最底层到最上层): 1.控件绘图面2.色块3.网格4.边框5.光标 在Paint事件中按上面顺序绘制2-5。 绘制网格很简单,根据色块大小隔一定距离画一道横(竖)线 绘制色块道理差不多,先获取当前坐标(行,列)的颜色(根据你自己定义的调色盘计算出来),然后填充一个方块,转到处理下一个坐标,直到全部行列都处理完。 然后绘制所有色块 从表面上看,是通过鼠标移动,选取每个色块获得颜色。其实不然。那样做,我就需要保存每个色块的颜色信息,白白浪费空间。我的实现方法是通过鼠标位置得知当前鼠标所在色块的坐标(行,列),然后用上面的颜色算法直接得到该色块的颜色,一句话搞定(Point pt是鼠标位置)。 标移动时会绘制光标,为了减少性能开销,不能直接Refresh()/Invalidate()控件,使用Invalidate(Rectangle)来重绘被鼠标弄脏的那个区域。所以用了两个小矩形保存旧光标和新光标的区域,然后在鼠标事件中更新(和鼠标取色一起)。 然后鼠标移动事件里重绘时稍微把区域扩大点(避免留下难看的边框)。 最后一行「OnColorChanged();是用来引发颜色改变事件。把事件写出来基本就完成了。 然后再完善下属性之类的,就可以在你的程序里使用了。 程序简单适合新手学习使用。 注意: 开发环境为Visual Studio 2010

110,579

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧