KingDZ 变菜鸟,每日一个C#小实例之---C#取色器

今天首先给大家带来的实例是C#取色器,目前互联网上各种版本的取色器多不胜数,其中好用的软件更是多如牛毛,今天我们就简单的讲解一个C#版本的取色器,诞生的过程,整个过程中,我会不断的完善我们的取色器,争取做一个可发布版本的取色器,也正好趁这个机会开发一个适合自己在实际编程中方便的取色去,哈哈,开始吧。

大家可以去其他网站上面找相应的软件,互联网上面也有很多很好的开源代码。博取众家之长,不断学习。

哦,对了,顺表告诉大家一句,我的开发环境是Window7+VS2010呵呵。

当然了,我们这次首先还是基于API接口开发,当然大家有更好的建议,欢迎告诉我,我喜欢更高的效率。哈哈。

首先我们要得到颜色,首先要做的就是得到屏幕上面某点的坐标了。哈哈

简单。上节课也实现了,这节课我们采用新的办法

Point p = new Point(MousePosition.X, MousePosition.Y);
lblX.Text = p.X.ToString();
lblY.Text = p.Y.ToString();

好了,得到鼠标的坐标了。对了,我把这个放在

tm_Tick

里面了,这个是时间控件的Tick事件哦。

首先为了下面的代码方便,我们需要首先了解一下什么是 IntPtr

C#中的IntPtr类型称为“平台特定的整数类型”,它们用于本机资源,如窗口句柄。

IntPtr 类型被设计成整数,其大小适用于特定平台。即是说,此类型的实例在 32 位硬件和操作

系统中将是 32 位,在 64 位硬件和操作系统上将是 64 位。

具体的用法,还有其中的奥妙,我想大家还是需要去了解一下。

http://msdn.microsoft.com/zh-cn/library/system.intptr.aspx

好了,我们来实现我们的取色器代码吧。

首先我们先用最简单的原理实现一个版本的取色器,我们实现的是移动鼠标显示桌面任意点的颜色。版本1当然是最简单的实现啦。

2

首先我们依然是调用API接口,

[DllImport("User32")]
public static extern IntPtr GetDC(IntPtr h);
[DllImport("gdi32")]
public static extern uint GetPixel(IntPtr h, Point p);

GetDC的说明,请参照官网

http://msdn.microsoft.com/en-us/library/dd144871(v=vs.85).aspx

GetPixel  该函数检索指定坐标点的像素的RGB颜色值。

http://msdn.microsoft.com/en-us/library/dd144909%28v=vs.85%29.aspx

建议英文好的童鞋可以好好看看上面的说明,对你绝对有好处滴。哈哈。

好了,说简单一些上面的两个函数,一个是取屏幕,另一个就是得到坐标点像素。

我们继续吧。

IntPtr h = GetDC(new IntPtr(0)); //取屏幕,0代表着全屏
uint color = GetPixel(h, p);        //取颜色喽
uint red = (color & 0xFF);            //转换红色
uint green = (color & 0xFF00) / 256;    //转换绿色
uint blue = (color & 0xFF0000) / 65536;//转换蓝色

上面的颜色转换使我们在编程中,经常用到的技巧,建议大家记住。

txtRGB.Text = string.Format("{0},{1},{2}", red, green, blue);
txtT.Text = color.ToString();
txtL.Text = "#" + red.ToString("x").PadLeft(2, '0') + green.ToString("x").PadLeft(2, '0') + blue.ToString("x").PadLeft(2, '0');

picColor.BackColor = Color.FromArgb((int)red,(int)green,(int)blue);

好了,最上面的代码也已完成了,呵呵,OK,简易版本的完成了。我们下面实现一个相对比较复杂的。大家觉得怎么样,这个只要一打开就可以会得到颜色了,但是可控制性不好。下面我们自己想办法控制,啥时间去颜色,啥时间不取颜色。

我们改变更一种写法来实现我们想要的效果。

首先声明几个坐标点。分别是,窗口起始左边,Window左下角和右下角。为什么出现这几个坐标呢,拜托。假如你想取到你取色器那个位置下面的坐标呢?你还取得到吗?覆盖着呢。

好了。开始

public Point formLoad, formLeft, formRight;

当然了,我们也需要一个及时取色的Timer

Timer tm;
首先在构造函数里面初始化数据。
Rectangle rect = Screen.PrimaryScreen.WorkingArea;
formLeft = new Point(0, rect.Height - this.Height);
formRight = new Point(rect.Width - this.Width, rect.Height - this.Height);
Screen.PrimaryScreen.WorkingArea得到屏幕工作区域,记住不包括任务栏啊,哈哈,怎么取到任务栏的颜色,你自己想办法吧。

下面我们还需要几个API来实现。

[DllImport("gdi32")]
private static extern IntPtr CreateDC(
string lpszDriver, // 驱动名称
string lpszDevice, // 设备名称
string lpszOutput, // 无用,可以设定位"NULL"
IntPtr lpInitData // 任意的打印机数据
);

上面这个API可以到http://msdn.microsoft.com/en-us/library/dd183490%28v=vs.85%29.aspx查找资料。

[DllImport("gdi32.dll")]
private static extern bool BitBlt(
IntPtr hdcDest, // 目标设备的句柄
int nXDest, // 目标对象的左上角的X坐标
int nYDest, // 目标对象的左上角的X坐标
int nWidth, // 目标对象的矩形的宽度
int nHeight, // 目标对象的矩形的长度
IntPtr hdcSrc, // 源设备的句柄
int nXSrc, // 源对象的左上角的X坐标
int nYSrc, // 源对象的左上角的X坐标
int dwRop // 光栅的操作值
);

http://msdn.microsoft.com/en-us/library/dd183370%28v=vs.85%29.aspx上面的API解释在这个地方。

当然,除了用API,还有其他的办法吗?当然有的,一会我们介绍。

2

btnGetColor_Click

该事件是按钮的单击事件,我们需要在里面定位我们的取色窗体。

formLoad = this.Location;
this.Location = formLeft;
this.TopMost = true;

我像上面的代码很好理解吧。

tm = new Timer();
tm.Interval = 1;
tm.Tick += new EventHandler(tm_Tick);
tm.Enabled = true;

好了计时器也在这里开始工作了。我们首先实现计时器的代码。

首先创建显示器的DC

IntPtr hdlDisplay = CreateDC("display",null,null,IntPtr.Zero);

从指定设备的句柄创建新的 Graphics 对象

Graphics g= Graphics.FromHdc(hdlDisplay);

创建只有一个象素大小的 Bitmap 对象

Bitmap bmp = new Bitmap(1, 1, g);

从指定 Image 对象创建新的 Graphics 对象

Graphics gimg = Graphics.FromImage(bmp);

获得屏幕的句柄与获得位图的句柄

IntPtr hdlScreen = g.GetHdc();
IntPtr hdlBmp = gimg.GetHdc();

把当前屏幕中鼠标指针所在位置的一个象素拷贝到位图中

BitBlt(hdlBmp, 0, 0, 1, 1, hdlScreen, MousePosition.X, MousePosition.Y, 13369376);

释放屏幕句柄和释放位图句柄

g.ReleaseHdc(hdlScreen);
gimg.ReleaseHdc(hdlBmp);

好了,到这取色的流程得到了,当然你也可以这么实现,下面的就不需要句柄了、

获得当前屏幕的

Screen screen = Screen.PrimaryScreen;
Rectangle rc = screen.Bounds;
int iWidth = rc.Width;
int iHeight = rc.Height;

创建一个和屏幕一样大的Bitmap

Image myImage = new Bitmap(iWidth, iHeight);

从一个继承自Image类的对象中创建Graphics对象

Graphics g = Graphics.FromImage(myImage);

复制全屏幕。得到全屏幕了,你想去像素也就简单多了。

g.CopyFromScreen(new Point(0, 0), new Point(0, 0), new Size(iWidth, iHeight));

好了,接着我们上面描述继续开发,我们需要的窗体,这里有一个技巧就是,用一个基本完全透明的窗体覆盖住Window剩下的我们好操作。

GetColors getColors = new GetColors();
getColors.Tag = this;
getColors.ShowDialog();

在这个新窗体中,我们在Load事件中简单的写两句即可。

this.MaximizedBounds = Screen.PrimaryScreen.Bounds;
this.WindowState = FormWindowState.Maximized;
this.FormBorderStyle = FormBorderStyle.None;

this.Opacity = 0.01;
最后的这个就是透明度了,哈哈,你可以改成 1 试试

窗体单击关闭

private void GetColors_Click(object sender, EventArgs e)
   {
       this.Close();
   }

当然更多的操作,比如窗体的鼠标,窗体的其他一些美工,都要靠自己了,你也可以,用其他的办法给窗体定位,或者,取指定窗体的颜色。

private void GetColors_MouseMove(object sender, MouseEventArgs e)
{
    MainForm Mymainform = (MainForm)this.Tag;
    if (e.X > Mymainform.Left && e.X < Mymainform.Left + Mymainform.Width && e.Y > Mymainform.Top && e.Y < Mymainform.Top + Mymainform.Width)
    {
        Mymainform.Location=Mymainform.Location == Mymainform.formLeft ? Mymainform.formRight:Mymainform.formLeft;
    }
}
当然这个方法就是解决咱们前面遇到的取色窗体覆盖的问题啦。哈哈,点不到,点不到.......

单击关闭透明窗体

tm.Enabled = false;
this.Location = formLoad;
this.TopMost = false;
释放资源,得到颜色
            picColor.BackColor = bmp.GetPixel(0, 0);


            txtARGB.Text = "0x" + picColor.BackColor.ToArgb().ToString("x").ToUpper();
            txtRGB.Text = picColor.BackColor.R.ToString().ToLower() + "," + picColor.BackColor.G.ToString().ToLower() + "," + picColor.BackColor.B.ToString().ToLower();
            txtL.Text = "#" + picColor.BackColor.R.ToString("x").PadLeft(2, '0') + picColor.BackColor.G.ToString("x").PadLeft(2, '0') + picColor.BackColor.B.ToString("x").PadLeft(2, '0');

            g.Dispose();
            gimg.Dispose();

            bmp.Dispose(); 

哈哈,好了,一个取色器做好了。

剩下的大家自己可以扩展了,可以按Ctrl去颜色,也可以取到颜色放到剪贴板中,总之呢,最难解决的就是拿到像素点颜色了,我们都已经拿到了,还有什么难的呢?

代码下载

GetColor.rar

posted @ 2011-09-16 13:56  KingDZ  阅读(5385)  评论(2编辑  收藏  举报