好看炫酷又好用的C#颜色选择器

前一段时间开发上位机功能需要用到颜色选择器功能,但是C#自带的颜色选择器操作繁琐,而且嵌入到上位机着实不好看,然后我在网上找了很久,发现很少有色轮形式的颜色选择器,所以我上github寻找,发现了一个宝藏——一个非常好看炫酷而且操作简单的的颜色选择器控件,推荐给大家。
【首先贴上github链接:适用于 Windows 窗体的 Cyotek 拾色器控件

首先贴出效果图看看是不是你想要的:

在这里插入图片描述

一、简单使用教程

此处是我使用Cyotek.Windows.Forms.ColorPickers库部分功能的一些经验和思路总结,没有太多深入地去学习,如果有哪位大佬有深入学习使用的话,可以推给我大家一起学习一下。

好了回到正文

1. 简单复习项目创建以及库的安装

(1)点击新建项目->选择Windows窗体应用->点击下一步->填写好项目名称和什么位置->点击创建
在这里插入图片描述
在这里插入图片描述
(2)打开NuGet 右键:ColorPicker->管理NuGet程序包
在这里插入图片描述
在浏览界面输入Cyotek.Windows.Forms.ColorPicker然后直接点击下载
在这里插入图片描述
(3)回到Form1.cs[设计],可以看到工具箱里面多了一个选项卡Cyotek Color Picker Controls
在这里插入图片描述

2. 实操

控件

控件类型 名称
3个主要控件 ColorWheel
ColorEditor
ColorGrid
5 个实用程序控件 ScreenColorPicker
RgbaColorSlider
HueColorSlider
LightnessColorSlider
SaturationColorSlider
1个管理组件 ColorEditorManager
1个对话框 ColorPickerDialog

(1)把需要用到的控件拖到Form1里面
在这里插入图片描述
在这里插入图片描述
(2)拖入colorEditorManger控件,然后按F4,绑定上面三个控件
在这里插入图片描述
运行效果:

请添加图片描述
(3)小小拓展一下
将想要的颜色通过串口发送出去
[效果演示]
在这里插入图片描述
上面所演示的效果是简单地在串口上位机加上一些颜色选择控件,然后获取到RGB值,并将RGB值放进通信协议里面,最后将数据通过串口发送出去,这样可以实现利用上位机控制RGB灯的颜色的效果。

实现步骤:

  1. 先写好串口上位机,教程可以看我的另一篇推文
  2. 把各种颜色选择控件按照上面的教程拉到窗体里面
  3. 绑定事件(即当颜色发送变化时触发的事件)
    (1)在左下角找到下面这个控件,按下F4
    在这里插入图片描述
    (2)点击闪电标志,双击ColorChanged旁边的空格子(这样就会自动生成一个函数,当颜色发送改变是会触发这个函数)
    在这里插入图片描述
  4. 事件代码实现
/**************************************************************************/
        #region 颜色选择工具拓展
        private void colorEditorManager1_ColorChanged(object sender, EventArgs e)
        {
    
    
            int r;
            int g;
            int b;
			
			//将获取到的RGB值进行数据类型转换
            r = Convert.ToInt32(colorWheel1.Color.R);
            g = Convert.ToInt32(colorWheel1.Color.G);
            b = Convert.ToInt32(colorWheel1.Color.B);

            //将RGB值嵌进通信协议(示例)
            byte[] temp = new byte[8];
            temp[0] = 0x66;     
            temp[1] = 0x04;
            temp[2] = 0x00;
            temp[3] = (byte)r;
            temp[4] = (byte)g;
            temp[5] = (byte)b;
            temp[6] = (byte)((0x04 ^ 0x00 ^ (byte)r ^ (byte)g ^ (byte)b) & 0xFF);   //检验
            temp[7] = 0x99;     

            richTextBox1.BackColor = Color.FromArgb(r,g,b);     //将颜色显示在richTextBox上面
            
            //打印数据
            richTextBox_ReceiveBox.Text += "发送的RGB值:" + colorWheel1.Color.R + "," + colorWheel1.Color.G + "," + colorWheel1.Color.B + "\n";
            richTextBox_ReceiveBox.Text += "数据流:";
            for (int i = 0; i < temp.Length; i++)
            {
    
    
                richTextBox_ReceiveBox.Text += temp[i].ToString("X2") + " ";
            }
            richTextBox_ReceiveBox.Text += "\n";

            Serial_SendData(temp);      //将字节数组通过串口发送
        }

        //串口发送函数
        void Serial_SendData(byte[] buff)
        {
    
                   
            try
            {
    
    
                serialPort1.Write(buff, 0, buff.Length);
            }
            catch
            {
    
    
                MessageBox.Show("串口通讯错误", "提示");
                serialPort1.Close();
                return;
            }
        }
        #endregion
        /**************************************************************************/

完整的代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
using System.IO;

namespace ColorPicker
{
    
    
    public partial class Form1 : Form
    {
    
    
        public Form1()
        {
    
    
            InitializeComponent();
        }

        /**************************************************************************/
        #region 初始化窗体
        private void Form1_Load(object sender, EventArgs e) //加载界面程序
        {
    
    
            try
            {
    
    
                string[] str = SerialPort.GetPortNames();   //获取连接到电脑的串口号并存进数组
                comboBox_PortNames.Items.Clear();           //清除串口号下拉框的内容
                comboBox_PortNames.Items.AddRange(str);     //将串口号添加到下拉框

                if (str.Length > 0)
                {
    
    
                    comboBox_PortNames.SelectedIndex = 0;   //设置ComboBox框的初始值
                    comboBox_BaudRate.SelectedIndex = 7;
                    comboBox_DataBit.SelectedIndex = 3;
                    comboBox_StopBit.SelectedIndex = 1;
                    comboBox_Parity.SelectedIndex = 2;
                }
                else
                {
    
    
                    MessageBox.Show("当前无串口连接!");
                }
            }
            catch
            {
    
    
                MessageBox.Show("无串口设备!/r/n请检查是否连接设备!/r/n请检查设备驱动!");
            }
        }
        #endregion
        /**************************************************************************/

        /**************************************************************************/
        #region 搜索串口(与初始化函数一样)
        private void button_Serach_Click(object sender, EventArgs e)
        {
    
    
            try
            {
    
    
                string[] str = SerialPort.GetPortNames();
                comboBox_PortNames.Items.Clear();
                comboBox_PortNames.Items.AddRange(str);

                if (str.Length > 0)
                {
    
    
                    comboBox_PortNames.SelectedIndex = 0;
                    comboBox_BaudRate.SelectedIndex = 7;
                    comboBox_DataBit.SelectedIndex = 3;
                    comboBox_StopBit.SelectedIndex = 1;
                    comboBox_Parity.SelectedIndex = 2;
                }
                else
                {
    
    
                    MessageBox.Show("当前无串口连接!");
                }
            }
            catch
            {
    
    
                MessageBox.Show("无串口设备!/r/n请检查是否连接设备!/r/n请检查设备驱动!");
            }
        }
        #endregion
        /**************************************************************************/

        /**************************************************************************/
        #region 打开串口
        private void button_OpenOrClose_Click(object sender, EventArgs e)
        {
    
    
            if (!serialPort1.IsOpen)
            {
    
    
                if (comboBox_PortNames.SelectedItem == null)
                {
    
    
                    MessageBox.Show("请选择正确的串口", "提示");
                    return;
                }

                //设置串口参数
                serialPort1.PortName = comboBox_PortNames.Text.ToString();  //serialPort1是serialPort组件的Name 
                serialPort1.BaudRate = Convert.ToInt32(comboBox_BaudRate.SelectedItem.ToString());
                serialPort1.DataBits = Convert.ToInt32(comboBox_DataBit.SelectedItem.ToString());

                //设置停止位
                if (comboBox_StopBit.Text == "One")
                {
    
    
                    serialPort1.StopBits = StopBits.One;
                }
                else if (comboBox_StopBit.Text == "Two")
                {
    
    
                    serialPort1.StopBits = StopBits.Two;
                }
                else if (comboBox_StopBit.Text == "OnePointFive")
                {
    
    
                    serialPort1.StopBits = StopBits.OnePointFive;
                }
                else if (comboBox_StopBit.Text == "None")
                {
    
    
                    serialPort1.StopBits = StopBits.None;
                }

                //设置奇偶校验位
                if (comboBox_Parity.Text == "Odd")
                {
    
    
                    serialPort1.Parity = Parity.Odd;
                }
                else if (comboBox_Parity.Text == "Even")
                {
    
    
                    serialPort1.Parity = Parity.Even;
                }
                else if (comboBox_Parity.Text == "None")
                {
    
    
                    serialPort1.Parity = Parity.None;
                }

                try
                {
    
    
                    //禁止操作组件
                    comboBox_PortNames.Enabled = false;
                    comboBox_BaudRate.Enabled = false;
                    comboBox_DataBit.Enabled = false;
                    comboBox_StopBit.Enabled = false;
                    comboBox_Parity.Enabled = false;
                    button_Serach.Enabled = false;

                    serialPort1.Open(); //设置完参数后打开串口
                    button_OpenOrClose.Text = "Close";  //更改Open按钮文本内容
                }
                catch
                {
    
    
                    MessageBox.Show("串口打开失败!");
                }

                //事件绑定方法,在DataReceived
                serialPort1.DataReceived += new SerialDataReceivedEventHandler(SerialDataReceive);  //打开串口后绑定数据接收
            }
            else if (button_OpenOrClose.Text == "Close")
            {
    
    
                try
                {
    
    
                    //允许操作组件
                    comboBox_PortNames.Enabled = true;
                    comboBox_BaudRate.Enabled = true;
                    comboBox_DataBit.Enabled = true;
                    comboBox_StopBit.Enabled = true;
                    comboBox_Parity.Enabled = true;
                    button_Serach.Enabled = true;


                    serialPort1.DiscardInBuffer();  //清除缓冲区的数据

                    serialPort1.Close();
                    button_OpenOrClose.Text = "Open";   //更改Close按钮文本内容
                }
                catch
                {
    
    
                    MessageBox.Show("串口打开失败!");
                }
            }
        }
        #endregion
        /**************************************************************************/

        /**************************************************************************/
        #region 接收串口数据
        /*
        开辟缓存区 根据具体协议内容获取一帧数据进行接收中断处理
         */
        //变量
        List<byte> sp_buffer = new List<byte>(4096);    //串口缓存区
        int sp_buffer_max = 4096;   //串口缓存区最大缓存字节数

        private void SerialDataReceive(object sender, SerialDataReceivedEventArgs e)
        {
    
    
            if (serialPort1.IsOpen == false)
            {
    
    
                serialPort1.Close();
                return;
            }


            int Byte_len = serialPort1.BytesToRead; //读取缓存的数据长度
            byte[] Rc_byte = new byte[Byte_len];

            serialPort1.Read(Rc_byte, 0, Byte_len);   //将缓存数据存储进字节数组里面

            if (sp_buffer.Count > sp_buffer_max)    //缓存超过字节数 先丢弃前面的字节  
                sp_buffer.RemoveRange(0, sp_buffer_max); //丢弃前面的字节0到sp_buffer_max

            sp_buffer.AddRange(Rc_byte);    //存入缓存区

            byte[] ruffer = new byte[9192]; //用来存放缓冲区的数据流

            //对数据流进行筛选,缓冲区每一组数据个数大于4则为我们想要的数据流
            if (sp_buffer.Count > 4)
            {
    
    
                sp_buffer.CopyTo(0, ruffer, 0, sp_buffer.Count);
                Task.Run(() => printf_data(ruffer, sp_buffer.Count, 1));  //打印数据流
            }
        }
        #endregion
        /**************************************************************************/

        /**************************************************************************/
        #region 打印数据流
        void printf_data(byte[] Frame, int Length, int T_R)   //打印串口数据
        {
    
    
            Int16 i_len;
            StringBuilder s = new StringBuilder();

            if (T_R == 0)
                s.Append("发送:");
            else
                s.Append("接收:");

            for (i_len = 0; i_len < Length; i_len++)       //打印字符串
            {
    
    
                s.Append(Frame[i_len].ToString("X2"));
                s.Append(" ");
            }

            s.Append("[" + DateTime.Now.ToString("HH:mm:ss fff") + "]");
            s.Append("\r\n");

            string str_show = s.ToString();
            MethodInvoker mi = new MethodInvoker(() =>
            {
    
    
                if (richTextBox_ReceiveBox.Lines.Count() > 20)
                    richTextBox_ReceiveBox.Clear();
                richTextBox_ReceiveBox.AppendText(str_show);
            });
            BeginInvoke(mi);
            /*
            textBox_com_data.Focus(); //获取焦点
            textBox_com_data.Select(textBox_com_data.TextLength, 0);//光标
            textBox_com_data.ScrollToCaret(); //滚动条*/
        }
        #endregion
        /**************************************************************************/

        /**************************************************************************/
        #region 发送数据
        private void button_Send_Click(object sender, EventArgs e)
        {
    
    
            if (serialPort1.IsOpen)
            {
    
    
                string[] sendbuff = richTextBox_send.Text.Split();  //分割输入的字符串,判断有多少个字节需要发送
                int Buff_Len = sendbuff.Length;
                byte[] buff = new byte[Buff_Len];

                for (int i = 0; i < sendbuff.Length; i++)
                {
    
    
                    buff[i] = byte.Parse(sendbuff[i], System.Globalization.NumberStyles.HexNumber); //格式化字符串为十六进制数值
                }

                try
                {
    
    
                    serialPort1.Write(buff, 0, buff.Length);    //写数据
                    Task.Run(() => printf_data(buff, Buff_Len, 0));
                }
                catch
                {
    
    
                    MessageBox.Show("发送失败!!");
                }
            }
            else
            {
    
    
                MessageBox.Show("串口未打开!");
            }

        }
        #endregion
        /**************************************************************************/

        /**************************************************************************/
        #region 清除输出框
        private void Clear_Click(object sender, EventArgs e)
        {
    
    
            richTextBox_ReceiveBox.Clear();     //清楚数据接收框数据
        }
        #endregion
        /**************************************************************************/

        /**************************************************************************/
        #region 颜色选择工具拓展
        private void colorEditorManager1_ColorChanged(object sender, EventArgs e)
        {
    
    
            int r;
            int g;
            int b;

            r = Convert.ToInt32(colorWheel1.Color.R);
            g = Convert.ToInt32(colorWheel1.Color.G);
            b = Convert.ToInt32(colorWheel1.Color.B);

            //将RGB值嵌进通信协议(示例)
            byte[] temp = new byte[8];
            temp[0] = 0x66;     
            temp[1] = 0x04;
            temp[2] = 0x00;
            temp[3] = (byte)r;
            temp[4] = (byte)g;
            temp[5] = (byte)b;
            temp[6] = (byte)((0x04 ^ 0x00 ^ (byte)r ^ (byte)g ^ (byte)b) & 0xFF);   //检验
            temp[7] = 0x99;     

            richTextBox1.BackColor = Color.FromArgb(r,g,b);     //将颜色显示在richTextBox上面
            
            //打印数据
            richTextBox_ReceiveBox.Text += "发送的RGB值:" + colorWheel1.Color.R + "," + colorWheel1.Color.G + "," + colorWheel1.Color.B + "\n";
            richTextBox_ReceiveBox.Text += "数据流:";
            for (int i = 0; i < temp.Length; i++)
            {
    
    
                richTextBox_ReceiveBox.Text += temp[i].ToString("X2") + " ";
            }
            richTextBox_ReceiveBox.Text += "\n";

            Serial_SendData(temp);      //将字节数组通过串口发送
        }

        //串口发送函数
        void Serial_SendData(byte[] buff)
        {
    
                   
            try
            {
    
    
                serialPort1.Write(buff, 0, buff.Length);
            }
            catch
            {
    
    
                MessageBox.Show("串口通讯错误", "提示");
                serialPort1.Close();
                return;
            }
        }
        #endregion
        /**************************************************************************/
    }
}

二、官方介绍

Cyotek.Windows.Forms.ColorPickers库包含一系列自定义控件和实用程序类,适用于使用颜色的 Windows 窗体应用程序。控件可用于通过 HSL 进行颜色选择ColorWheel,ColorGrid 具有许多自定义选项,ColorEditor用于通过 RGB 或 HSL 输入颜色,以及ScreenColorPicker用于从正在运行的应用程序中捕获颜色。

调色板可以以多种不同的格式加载和保存,包括 Adob​​e PhotoShop 色板文件、JASC 调色板、Gimp 调色板等(请参阅下面的调色板和外部调色板文件)。

有关这些控件的更多信息,请参阅cyotek.com 上带有标签的文章。colorpicker

(1)获取Lib

获取库的最简单方法是通过NuGet
Install-Package Cyotek.Windows.Forms.ColorPicker
如果您不使用 NuGet,可以从GitHub 发布页面获取预编译的二进制文件。

当然,您可以随时获取源代码并自己构建!

(2)控件

控件类型 名称
3个主要控件 ColorWheel
ColorEditor
ColorGrid
5 个实用程序控件 ScreenColorPicker
RgbaColorSlider
HueColorSlider
LightnessColorSlider
SaturationColorSlider
1个管理组件 ColorEditorManager
1个对话框 ColorPickerDialog

1. 颜色网格控件 ColorGrid Controls

ColorGrid 控件演示
此控件显示颜色网格,并支持主调色板和自定义调色板。有几个属性可用于配置控件的显示,也有一些行为选项,例如内置的颜色编辑和支持自动添加不在主调色板中的新颜色。

2.色轮控制 ColorWheel

ColorWheel控制演示
此控件显示 RGB 颜色的径向轮,并允许从轮中的任何点进行选择。ShowAngleArrow、ShowCenterLines 和ShowSaturationRing属性可用于显示有用的装饰,而Lightness和Alpha属性可用于组成最终颜色,但不能在轮子上直接编辑。
SecondaryColors和SecondarySelectionSize属性允许您在轮盘上显示其他颜色例如用于显示关系。

3.颜色滑块控件 ColorSlider

ColorSlider 控件演示
一组控件(从单个基类继承),允许通过彩色条选择值。与 TrackBar控件类似,您有几个选项可用于指定拖动手柄的位置和条形方向。您还可以自定义填充和轮廓颜色,或将其完全替换为自定义图像。

4.颜色编辑器控件 ColorEditor

ColorEditor 控件演示
此控件允许通过标准界面编辑 RGB 或 HSL 颜色。您还可以通过 6 或 8 个字符的十六进制表示法输入颜色,或从命名的 Web 和系统颜色中进行选择。
可以通过 ShowAlphaChannel和PreserveAlphaChannel属性配置 alpha 通道的使用。ShowHex、ShowHsl和ShowRgb属性可用于显示或隐藏编辑器组件或者,NubSizeNubColor和NubOutlineColor 属性可用于自定义滑块的外观。

5.ScreenColorPicker 控件

ScreenColorPicker 控件演示
此控件允许用户从屏幕上显示的任何像素中选择颜色。用户可以通过单击并拖动控件来触发操作,也可以通过该CaptureMouse方法以编程方式完成,允许通过其他操作(例如热键)触发选择。该Zoom属性可用于设置预览的网格大小。

6.颜色选择器对话框窗体 ColorPickerDialog

ColorPickerDialog 表单演示
此表单将前面的控件放在一个随时可用的对话框中。
通过该属性支持自定义颜色CustomColors,用户还可以将外部调色板文件加载或保存到其中。您可以使用ShowLoadShowSave属性来启用或禁用此功能,并使用CustomColorsLoadingCustomColorsSaving事件来覆盖内置行为并提供您自己的逻辑。

4.颜色编辑器管理器 ColorEditorManager

ColorEditorManager 组件演示
这是一个非 GUI 组件,您可以将其拖放到表单上,并绑定到此库中的其他控件。当Color 一个控件的属性发生变化时,它会反映在其他控件中,而无需抬起手指。如果您从多个控件创建复合显示,这很有用。

调色板和外部调色板文件

ColorGrid控件有CustomColors和Colors属性能够返回一个颜色集合。这两个属性使开发人员可以更轻松地保持单独的主调色板,同时具有自定义颜色的灵活性,尽管它确实使控件的内部逻辑有点复杂!如果您尝试将控件设置为当前未定义的值,网格将自动填充自定义颜色。
除了手动填充颜色集合实例外,您还可以加载外部调色板文件。支持以下调色板格式:

Adobe 颜色表 (.act)
Adobe PhotoShop 色板 (
.aco)
GIMP (.gpl)
豪华油漆 (
.bbm; .lbm) [只读]
JASC (
.pal)
Paint.NET (.txt)
原始 RGB 三元组 (
.pal)
除了 ILBM 图像格式之外,所有其他格式都可以导出和导入。

通过添加实现IPaletteSerializer. (或任何使用静态方法的 ColorPickerDialog自定义代码 PaletteSerializer)将通过反射自动检测并提供自定义调色板。

键盘支持

所有 GUI 组件, ScreenColorPicker包括完整的键盘/焦点支持除外。许多控件支持SmallChange和LargeChange影响导航键处理方式的属性。虽然在这种情况下ColorWheel它并不是真正的奖励…但这就是ColorEditor控制最适合的!

猜你喜欢

转载自blog.csdn.net/weixin_49959955/article/details/124979691