c# 自绘控件(一) 之 颜色选择器

一、效果图

在这里插入图片描述
效果图忘记移动到窗口边缘了,移动到窗口边缘会自动调整位置的。

二、说明

1、控件上还存在一点小问题,有知道解决方案的,请不吝赐教,多谢!
2、控件是绘制的,没有使用winform标准库中的控件。
3、控件是我在做其他软件时需要的,因此增加了Word中选色的功能。
4、还有几天就要考一建了,最近太忙只有晚上放松时间才写写代码,暂时没有时间检查修改小问题,后期上传了源码,有发下问题的请告知下,我有时间了会修改更新,上传代码估计要等到9月中旬我忙完了这段时间了。
5、参考内容:
1.颜色色相值计算:https://www.cnblogs.com/grenet/archive/2009/12/14/1623796.html,其实这个没啥用,但要知道原理,c#Color类有GetHue方法。
2.色彩空间:https://blog.csdn.net/qq_41375318/article/details/118550040
3.Windows画图软件和PS软件中颜色选择窗口
4.OpenXml的Color类:https://learn.microsoft.com/zh-cn/dotnet/api/documentformat.openxml.wordprocessing.color?view=openxml-2.8.1

三、思路与存在的问题

1、控件分为两部分,一部分是在窗口中显示使用,一部分是弹出选择。
2、考虑到类似ComBox那样的弹出下拉列表,可以超出父窗口的范围。因此控件弹出层使用的是窗口,而不是控件。(不懂ComBox的效果原理,目前做出来的还是存在一点问题)
3、目前存在一个缺点就是,弹出颜色选择后,如果没有点击弹出层的情况下,直接点击控件所在窗口中无法获取焦点的控件(如:label),窗口不会自动隐藏。
4、请教大佬,有谁懂ComBox弹出层效果实现的原理,一定请私聊或评论中告诉我一下,跪谢了!!!
5、代码框架
WordColor项目
控件在WordColor项目中,简单说明下类的作用吧

1.ColorPicker 类

控件显示类,就是在应用窗口显示的控件类。

2.Popup 类

控件弹出层类。

3.ColorValue 类

定义的WordColor类,Word中颜色的设置是由颜色、主题、阴影、亮度几个因素构成的,因此需要封装下。

4.CustomColorType 枚举

弹出层为“自定义颜色选择”时,显示的方式,与是否可以输入RGB或Html颜色进行调整的枚举。

5.DisplayType 枚举

弹出层的类型,一共有四种。

6.DispalyData 命名空间

弹出层显示的数据。

6.1 ColorPlateBase类

四种弹出层显示的基类。

6.2 HeightColor类

Word中高亮标记颜色选择类

6.3 ThemeColor类

Word中颜色选择类

6.4 CommonColor类

常用颜色选择类(参考率Windows自带画图软件的常用颜色)

6.5 CustomColor类

自定义颜色选择类,这个类最为麻烦

7.Ext 命名空间

扩展类。

7.1 ColorHelper类

颜色帮助类,主要是生成自定义颜色的色带,根据色带选中,生成对应颜色图。这里的计算方法是我根据PS中颜色选择的方法一步一步推导出的数学式计算出来的。在网上找了很久都没有找到,只能从0学习颜色的构成、色相度关系等,然后再推导公式。

7.2 DrawPath类

生成一些固定图形的类,比如生成三角形(正三角、倒三角、斜三角)、圆角矩形等

7.3 Number类

只有一个方法,就是将字符串转为32位整数

7.4 PointExt类

Point或Rectangle偏移方法,主要用到的是比例缩放、固定值缩放Rectangle等

7.5 Shifting类

Point或Rectangle偏移方法,包括左右偏移,大小偏移等

四、关键部分代码

1、ColorPicker类

    #region ==声明委托==
    /// <summary>
    /// 声明选择颜色的委托
    /// </summary>
    /// <param name="c"></param>
    public delegate void SelectedColor(object sender,Color? c);

    /// <summary>
    /// 定义弹出层完成事件
    /// </summary>
    /// <param name="o"></param>
    public delegate void PopupedEvent(object sender);

    /// <summary>
    /// 点击更多颜色选择的按钮
    /// </summary>
    /// <param name="sender"></param>
    public delegate void MoreBtnClick(object sender);

    #endregion


    public partial class ColorPicker : UserControl
    {
        #region ==私有成员===

        /// <summary>
        /// 颜色选择器样式
        /// </summary>
        private DisplayType displayType = DisplayType.HightColor;

        /// <summary>
        /// 默认的颜色值
        /// </summary>
        private ColorValue colorValue = new ColorValue(null,null);

        /// <summary>
        /// 弹出层对象
        /// </summary>
        private Popup? Popup;

        /// <summary>
        /// 选择后的颜色
        /// </summary>
        protected Rectangle ColorRect = Rectangle.Empty;

        /// <summary>
        /// 选择器中按钮部分
        /// </summary>
        protected Rectangle ColorBtnRect = Rectangle.Empty;

        /// <summary>
        /// 渐变设图像保存
        /// </summary>
        public Bitmap Gradient = new Bitmap(1, 1);

        /// <summary>
        /// 绘制Gradient的颜色块大小,默认8像素
        /// </summary>
        protected CustomColorType customColorType = CustomColorType.Vertical;

        #endregion



        #region ==声明事件==
        /// <summary>
        /// 声明选择颜色事件
        /// </summary>
        [Category("附加"), Description("选择颜色事件"), Browsable(true)]
        public event SelectedColor? SelectedColor;

        /// <summary>
        /// 弹出下拉选择框的事件
        /// </summary>
        [Category("附加"), Description("弹出下拉选择框的事件"), Browsable(true)]
        public event PopupedEvent? DroppedDown;

        /// <summary>
        /// 点击更多颜色选择的按钮
        /// </summary>
        [Category("附加"), Description("点击更多颜色选择的按钮"), Browsable(true)]
        public event MoreBtnClick? MoreBtnClick;

        #endregion

        #region ==属性==



        private Color borderColor = Color.Black;

        /// <summary>
        /// 设置边框颜色
        /// </summary>
        [Category("外观"), Description("设置边框颜色"), Browsable(true)]
        public Color BorderColor { get => borderColor; set { borderColor = value; this.Refresh(); } }

        /// <summary>
        /// 颜色选择器样式
        /// </summary>
        [Category("外观"), Description("设置弹出颜色选择器的样式\r\ndddd"), Browsable(true)]
        public DisplayType DisplayType { get => displayType; 
            set { 
                displayType = value;
                if (displayType == DisplayType.HightColor) colorValue = new(null, null);                    // 当转到高亮标记时,需要清空所有的颜色
                else colorValue = new(colorValue.Color);                                                    // 转化到其他,只需要初始化颜色即可,颜色值可以存在
                this.Refresh(); 
            } 
        }

        /// <summary>
        /// 设置 或 获取颜色值
        /// </summary>
        [Browsable(false)]      // 不显示在属性面板
        public ColorValue ColorValue { get => colorValue; set { colorValue = value; this.Refresh(); } }

        /// <summary>
        /// 设置 或 获取 选中颜色
        /// </summary>
        [Category("数据"), Description("设置默认选中颜色"), Browsable(true)]
        public Color Value { get => ColorValue.Color; 
            set{ 
                ColorValue.Color = value; 
                this.Refresh(); 
            } 
        }

        
        [Category("数据"), Description("设置自定义颜色时显示的方式"), Browsable(true)]
        public CustomColorType CustomColorType
        {
            get => customColorType;
            set =>customColorType = value;
        }


        /// <summary>
        /// 设置 或 获取 选中颜色
        /// </summary>
        [Category("其他"), Description("在“自定义颜色选择”中允许按回车确认选择颜色(在颜色编辑状态下回车也会返回结果)"), Browsable(true)]
        public bool Confirm { set; get; } = true;

        #endregion

        #region ===构造函数与初始化===



        public ColorPicker()
        {
            InitializeComponent();
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            Init();
            CreateImage();       // 可能占用时间,创建一个线程来计算
        }

        protected void Init()
        {
            // 初始化 两个区域
            this.ColorBtnRect = new Rectangle(this.Width - this.Height, 0, this.Height, this.Height);
            this.ColorRect = new Rectangle(0, 0, this.Width - this.Height, this.Height);
        }

        private void ColorPicker_Load(object sender, EventArgs e)
        {
            //if (this.displayType == DisplayType.ThemeColor)
            //{
            //    this.colorValue.Color = Color.Empty;
            //    this.colorValue.Value = "auto";
            //}
           
        }

        #endregion

        #region ===私有方法===


        /// <summary>
        /// 创建弹出层
        /// </summary>
        private void CreatePopup()
        {
            if (Popup == null || Popup.IsDisposed)
            {
                Popup = new Popup(this);
                Point point = this.PointToScreen(new Point(0, this.Height));    // 计算出当前控件距离屏幕的位置
                Popup.Location = point;
                //this.Parent.Controls.Add(Popup);        // 必须等初始化完成后才能添加到父控件
                this.ParentForm.MouseClick += ParentForm_MouseClick;
                this.ParentForm.Move += ParentForm_Move;
                this.ParentForm.SizeChanged += ParentForm_SizeChanged;


            }
        }

        /// <summary>
        /// 创建自定义颜色选择的 渐变色图片
        /// </summary>
        private void CreateImage()
        {
            //await Task.Run(() => { Gradient = CustomColor.GetColorBrightness(ColorTranslator.FromHtml("#4ad435"),200); });       // 可能占用时间,创建一个线程来计算
            //this.Refresh();
        }


        /// <summary>
        /// 主窗口移动
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <exception cref="NotImplementedException"></exception>
        private void ParentForm_SizeChanged(object? sender, EventArgs e)
        {
            if (!(this.Popup == null || this.Popup.IsDisposed))
            {
                Popup.Dispose();
            }
        }

        /// <summary>
        /// 窗口移动
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <exception cref="NotImplementedException"></exception>
        private void ParentForm_Move(object? sender, EventArgs e)
        {
            if (Popup != null)
            {
                Popup.Dispose();
            }
        }

        /// <summary>
        /// 定义父窗口鼠标点击事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ParentForm_MouseClick(object? sender, MouseEventArgs e)
        {
            // 这里存在问题,点击到不接受焦点的对象,则无法进入此函数
            if (!(this.Popup == null || this.Popup.IsDisposed))     // 弹出窗口存在
            {
                Rectangle rect = new Rectangle(this.Location, this.Size);
                if (this.Popup.Visible == true && !rect.Contains(e.Location))
                {
                    this.Popup.Dispose();       // 每次的关闭都是释放资源,需要的时候重新加载
                }
            }
        }


        /// <summary>
        /// 获取弹出层的位置坐标点
        /// </summary>
        /// <returns></returns>
        private Point GetPopupLocation()
        {
            if (Popup == null) return Point.Empty;


            Point point = this.PointToScreen(new Point(0, this.Height));    // 计算出当前控件距离屏幕的位置
            if (point.Y + this.Popup.Height > Screen.PrimaryScreen.WorkingArea.Bottom)      // 底边超出了任务栏顶部的位置
            {
                point.Y = point.Y - this.Height - this.Popup.Height;
            }

            if (point.X + this.Popup.Width > Screen.PrimaryScreen.WorkingArea.Right)      // 底边超出了右边的位置
            {
                point.X = point.X - (this.Popup.Width - this.Width);
            }
            return point;
        }

        #endregion

        #region ==自绘控件==



        protected override void OnPaint(PaintEventArgs e)
        {
            DrawBut(e.Graphics);
        }

        /// <summary>
        /// 画按钮边框
        /// </summary>
        /// <param name="g"></param>
        protected virtual void DrawBut(Graphics g)
        {
            using (Pen pen = new Pen(Color.Red))
            {
                
                g.DrawRectangle(Pens.Gray, this.ColorBtnRect);                          // 画按钮部分边框
                
                using (Brush brush = new SolidBrush(this.ForeColor))
                {
                    float val = MoveRect.IsEmpty ? 0.5f : 0.6f;
                    g.FillPath(brush, DrawPath.DrawInvertedTriangle(this.ColorBtnRect.Scale(val)));        // 画 按钮内部三角形
                }
                // 判断是否存在颜色
                if (this.ColorValue.Color.IsEmpty)
                {
                    if (this.DisplayType == DisplayType.ThemeColor)
                    {
                        Rectangle rect = this.ColorRect.Scale(-3);
                        rect.Width = rect.Height;
                        g.FillRectangle(Brushes.Black, rect);                               // 画 自动颜色 黑色方块
                        

                        Rectangle tRect = this.ColorRect.Scale(-3);
                        tRect.X = rect.Right + rect.X;                                      // 文字区域X坐标计算
                        tRect.Width = this.ColorRect.Width - tRect.X - rect.X;              // 计算文字区域宽度
                        
                        SizeF sizeF = g.MeasureString("自动", new Font("宋体", tRect.Height / 2));
                        if (sizeF.Width < tRect.Width)
                        {
                            StringFormat sf = new StringFormat() { LineAlignment = StringAlignment.Center, FormatFlags = StringFormatFlags.LineLimit };
                            g.DrawString("自动", new Font("宋体", tRect.Height / 2), Brushes.Black, tRect, sf);        // 绘制文字
                        }
                        
                    }
                    else if (this.DisplayType == DisplayType.HightColor)
                    {
                        Rectangle rect = this.ColorRect.Scale(-3);
                        rect.Width = rect.Height;
                        g.FillRectangle(Brushes.White, rect);                               // 画 自动颜色 黑色方块
                        g.DrawLine(Pens.Red, rect.X, rect.Bottom, rect.Right, rect.Y); // 填充无颜色图形框中斜线
                        g.DrawRectangle(Pens.Gray, rect);

                        Rectangle tRect = this.ColorRect.Scale(-3);
                        tRect.X = rect.Right + rect.X;                                      // 文字区域X坐标计算
                        tRect.Width = this.ColorRect.Width - tRect.X - rect.X;              // 计算文字区域宽度

                        SizeF sizeF = g.MeasureString("无", new Font("宋体", tRect.Height / 2));
                        if (sizeF.Width < tRect.Width)
                        {
                            StringFormat sf = new StringFormat() { LineAlignment = StringAlignment.Center, FormatFlags = StringFormatFlags.LineLimit };
                            g.DrawString("无", new Font("宋体", tRect.Height / 2), Brushes.Black, tRect, sf);        // 绘制文字
                        }
                    }


                }
                else
                {
                    using (Brush brush = new SolidBrush(this.ColorValue.Color))
                    {
                        g.FillRectangle(brush, this.ColorRect);         // 画颜色选择部分
                    }
                }
                g.DrawRectangle(pen, this.DisplayRectangle.Shifting(0, 0, -1, -1));        // 画 整个的边框   

            }
        }
        #endregion

        #region ===处理鼠标相关===

        /// <summary>
        /// 定义一个鼠标经过的项区域【多定义一个变量,是由于this.ColorBtnRect不能设置为空】
        /// </summary>
        private Rectangle MoveRect = new Rectangle();

        /// <summary>
        /// 光标移动
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (!MoveRect.IsEmpty && this.MoveRect.Contains(e.Location)) return;
            if (this.ColorBtnRect.Contains(e.Location))
            {
                this.MoveRect = this.ColorBtnRect;
            }
            else
            {
                this.MoveRect = Rectangle.Empty;
            }
            this.Refresh();
        }

        /// <summary>
        /// 光标点击
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseClick(MouseEventArgs e)
        {
            Stopwatch stopwatch = Stopwatch.StartNew();
            if (e.Button != MouseButtons.Left) return;
            CreatePopup();          // 只有在弹出的时候在根据 属性值创建对象
            if (Popup != null)
            {
                Popup.TopLevel = true;
                Popup.Location = GetPopupLocation();
                Popup.Visible = !Popup.Visible;
                
                if (this.DroppedDown != null) DroppedDown(this);        // 添加事件
                Debug.WriteLine("加载时长:"+stopwatch.ElapsedMilliseconds);
            }

        }

        /// <summary>
        /// 光标离开
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseLeave(EventArgs e)
        {
            // 鼠标离开了,恢复原本的显示
            this.MoveRect = Rectangle.Empty;
            this.Refresh();
        }

        #endregion

        #region ==重写其他事件==

        /// <summary>
        /// 当控件大小改变时
        /// </summary>
        /// <param name="e"></param>
        protected override void OnSizeChanged(EventArgs e)
        {
            //base.OnSizeChanged(e);
            Init();
            this.Refresh();
        }

        /// <summary>
        /// 失去焦点
        /// </summary>
        /// <param name="e"></param>
        protected override void OnLostFocus(EventArgs e)
        {
            if (!(this.Popup == null || this.Popup.IsDisposed))     // 窗口存在
            {
                if (this.Popup.Focused == false)     // 弹出层没有焦点,且
                {
                    if (this.displayType != DisplayType.CustomColor)        // 【自定义颜色】比较特殊,需要拥有焦点的。因此当颜色选择器失去焦点他不能隐藏
                    {
                        this.Popup.Dispose();       // 每次的关闭都是释放资源,需要的时候重新加载
                    }
                    else
                    {
                        if (this.Popup.ContainsFocus!=true)
                        {
                            this.Popup.Dispose();       // 每次的关闭都是释放资源,需要的时候重新加载
                        }
                    }
                   
                }
                
                
            }
        }

        #endregion

        #region ==弹出层传递通知==

        /// <summary>
        /// 选择颜色事件,方便弹出层调用
        /// </summary>
        internal void SelectedColorEvent()
        {
            if (this.SelectedColor!=null)
            {
                SelectedColor(this, this.colorValue.Color);
            }
        }

        /// <summary>
        /// 点击更多颜色选择的按钮事件,方便弹出层调用
        /// </summary>
        internal void MoreBtnClickEvent()
        {
            if (this.MoreBtnClick != null)
            {
                MoreBtnClick(this);
            }
        }

        #endregion

    }

2. ColorPlateBase类

    internal abstract class ColorPlateBase
    {
        /// <summary>
        /// 绘图的窗口
        /// </summary>
        protected Popup Popup;

        #region ==属性==


        /// <summary>
        /// 颜色的Html值
        /// </summary>
        private List<string> colorHtml = new List<string>();

        /// <summary>
        /// 颜色的Html值
        /// </summary>
        public List<string> ColorHtml { 
            get { return colorHtml; } 
            protected set { colorHtml = value; } 
        }

        /// <summary>
        /// 对应的颜色名称
        /// </summary>
        private List<string> colorName = new List<string>();

        /// <summary>
        /// 对应的颜色名称
        /// </summary>
        public List<string> ColorName
        {
            get { return colorName; }
            protected set { colorName = value; }
        }

        /// <summary>
        /// 绘制颜色块的范围
        /// </summary>
        private List<Rectangle> drawColorRects = new List<Rectangle>();

        /// <summary>
        /// 绘制颜色块的范围
        /// </summary>
        public List<Rectangle> DrawColorRects
        {
            get { return drawColorRects; }
            protected set { drawColorRects = value; }
        }

        #endregion

        #region ==字段==

        /// <summary>
        /// 弹出层默认大小
        /// </summary>
        public Size DefaultSize;

        /// <summary>
        /// 准备选中的颜色块
        /// </summary>
        public Rectangle SelectRect = Rectangle.Empty;

        /// <summary>
        /// 已选中的颜色块
        /// </summary>
        public Rectangle SelectedRect = Rectangle.Empty;

        /// <summary>
        /// 跳转按钮区域
        /// </summary>
        public Rectangle BtnRect = Rectangle.Empty;

        #endregion

        /// <summary>
        /// 颜色面板基类
        /// </summary>
        /// <param name="popup">颜色面板弹出层对象</param>
        /// <param name="size">弹出层默认大小</param>
        public ColorPlateBase(Popup popup,Size size)
        {
            this.Popup = popup;
            DefaultSize = size;
            popup.Size = DefaultSize;
        }


        /// <summary>
        /// 绘制界面
        /// </summary>
        /// <param name="g"></param>
        public abstract void Paint(PaintEventArgs e);

        /// <summary>
        /// 初始化计算画图区间
        /// </summary>
        public abstract void InitCalculate();

        /// <summary>
        /// 获取颜色值
        /// </summary>
        /// <param name="index">colorHtml对应索引的值</param>
        /// <returns></returns>
        public abstract ColorValue GetColorValue(int index);
    }

3. Popup类

    internal class Popup : Form
    {
        #region ===私有成员===

        /// <summary>
        /// 当前临时跳转过来的
        /// </summary>
        private DisplayType nowDisplayType;

        /// <summary>
        /// 颜色选择基类
        /// </summary>
        private ColorPlateBase ColorPlateBase;


        /// <summary>
        /// 绑定的颜色选择器
        /// </summary>
        internal ColorPicker ColorPicker;


        #endregion

        #region ===重写字段(不激活窗口)===

        /// <summary>
        /// 不抢焦点,非活动窗口【但就不能通过失去焦点而消失】
        /// <para>直接通过重载以下ShowWithoutActivation 属性(默认为false)为true 来快速实现显示窗口时不将其激活</para>
        /// </summary>
        protected override bool ShowWithoutActivation => true;

        #endregion



        #region ===构造函数及初始化===

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="colorPicker">颜色选择器</param>
        /// <exception cref="ArgumentException"></exception>
        public Popup(ColorPicker colorPicker)
        {
            InitializeComponent();
            this.nowDisplayType = colorPicker.DisplayType;
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            this.ColorPicker = colorPicker;
            this.Visible = false;
            switch (this.ColorPicker.DisplayType)
            {
                case DisplayType.HightColor:
                    ColorPlateBase = new HeightColor(this);
                    break;
                case DisplayType.ThemeColor:
                    ColorPlateBase = new ThemeColor(this);
                    break;
                case DisplayType.CommonColor:
                    ColorPlateBase = new CommonColor(this);
                    break;
                case DisplayType.CustomColor:
                    ColorPlateBase = new CustomColor(this);
                    break;
                default:
                    throw new ArgumentException("ColorPicker 没有这个值");

            }
            CalculateDefaultSelected();
        }


        private void InitializeComponent()
        {
            SuspendLayout();
            // 
            // Popup
            // 
            AutoValidate = AutoValidate.Disable;
            ClientSize = new Size(150, 150);
            ControlBox = false;
            DoubleBuffered = true;
            FormBorderStyle = FormBorderStyle.None;
            MaximizeBox = false;
            MdiChildrenMinimizedAnchorBottom = false;
            MinimizeBox = false;
            Name = "Popup";
            ShowIcon = false;
            ShowInTaskbar = false;
            StartPosition = FormStartPosition.Manual;
            ResumeLayout(false);
        }

        /// <summary>
        /// 计算默认选择区域
        /// </summary>
        private void CalculateDefaultSelected()
        {
            for (int i = 0; i < this.ColorPlateBase.ColorHtml.Count; i++)
            {
                if (this.ColorPlateBase.ColorHtml[i] == ColorTranslator.ToHtml(this.ColorPicker.Value).Replace("#",""))
                {
                    if (this.ColorPlateBase.DrawColorRects.Count > i)
                    {
                        this.ColorPlateBase.SelectedRect = this.ColorPlateBase.DrawColorRects[i];
                    }
                    return;
                }
            }
        }

        #endregion

        #region ===重绘===


        /// <summary>
        /// 重绘
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPaint(PaintEventArgs e)
        {

            ColorPlateBase?.Paint(e);            // 显示颜色面板的类型
            e.Graphics.DrawRectangle(Pens.Gray, this.ClientRectangle.Shifting(0, 0, -1, -1));       // 画边框
            DrawSelect(e);      // 画选中部分
        }

        /// <summary>
        /// 应当在画完全部内容后调用
        /// </summary>
        /// <param name="e"></param>
        protected virtual void DrawSelect(PaintEventArgs e)
        {
            // 画选中框
            if (!this.ColorPlateBase.SelectRect.IsEmpty)
            {
                using (var pen = new Pen(Color.Black))
                {
                    pen.Width = 2f;

                    Rectangle rect = this.ColorPlateBase.SelectRect;

                    // ============由于右侧和底边画画框是画不到的,因此,调整画选中框===============
                    if (this.ColorPlateBase.SelectRect.Width == this.Width) rect = rect.Shifting(0, 0, -2, 0);       // 如果当前选中的区域宽度与控件宽度一致
                    if (this.ColorPlateBase.SelectRect.Top == 0) rect = rect.Shifting(0, 2, 0, -2);                        // 顶部“自动颜色”调整
                    if (this.ColorPlateBase.SelectRect.Bottom == this.Height) rect = rect.Shifting(0, 0, 0, -2);     // 底部“选择其他颜色”调整
                    e.Graphics.DrawRectangle(pen, rect);
                }
            }
            // 画原有选中区域
            if (!this.ColorPlateBase.SelectedRect.IsEmpty)
            {
                using (var pen = new Pen(Color.Black))
                {
                    pen.Width = 2f;
                    Rectangle rect = this.ColorPlateBase.SelectedRect;
                    // ============由于右侧和底边画画框是画不到的,因此,调整画选中框===============
                    if (this.ColorPlateBase.SelectedRect.Width == this.Width) rect = rect.Shifting(0, 0, -2, 0);       // 如果当前选中的区域宽度与控件宽度一致
                    if (this.ColorPlateBase.SelectedRect.Top == 0) rect = rect.Shifting(0, 2, 0, -2);                        // 顶部“自动颜色”调整
                    if (this.ColorPlateBase.SelectedRect.Bottom == this.Height) rect = rect.Shifting(0, 0, 0, -2);     // 底部“选择其他颜色”调整
                    e.Graphics.DrawRectangle(pen, rect);
                }
            }
        }


        #endregion

        #region ===鼠标相关事件重写===


        /// <summary>
        /// 光标移除控件范围
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseLeave(EventArgs e)
        {
            ColorPlateBase.SelectRect = Rectangle.Empty;
            this.Refresh();
        }

        /// <summary>
        /// 鼠标移动
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (ColorPlateBase.GetType() == typeof(CustomColor))
            {
                ((CustomColor)ColorPlateBase).MouseMove(e);
                return;
            }

            if (!ColorPlateBase.SelectRect.IsEmpty && ColorPlateBase.SelectRect.Contains(e.Location))
            {
                return;     // 当前光标还没有移除范围
            }

            // 查找当前 光标移动的位置 是否在那个颜色块中,如果在,则设置选中区域,并刷新返回。
            for (int i = 0; i < ColorPlateBase.DrawColorRects.Count; i++)
            {
                if (ColorPlateBase.DrawColorRects[i].Contains(e.Location))
                {

                    this.ColorPlateBase.SelectRect = ColorPlateBase.DrawColorRects[i];
                    this.Refresh();
                    return;
                }
            }
            // 没有找到则设置为空
            ColorPlateBase.SelectRect = Rectangle.Empty;
            this.Refresh();
        }

        /// <summary>
        /// 鼠标点击
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseClick(MouseEventArgs e)
        {
            if (ColorPlateBase.GetType() == typeof(CustomColor))
            {
                ((CustomColor)ColorPlateBase).MouseClick(e);
                return;
            }

            for (int i = 0; i < ColorPlateBase.DrawColorRects.Count; i++)
            {
                if (ColorPlateBase.DrawColorRects[i].Contains(e.Location))
                {
                    if (i == ColorPlateBase.DrawColorRects.Count - 1)           // 最后一个选择框
                    {
                        if (this.ColorPicker.DisplayType == DisplayType.ThemeColor)         // 主题颜色
                        {
                            // 【主题颜色的最后一个颜色框是按钮框】这里有个按钮需要单独做逻辑的处理
                            ColorPlateBase = new CommonColor(this);
                            this.nowDisplayType = DisplayType.CommonColor;
                            this.ColorPicker.MoreBtnClickEvent();       // 通知ColorPicker已经点击了选择更多颜色
                            this.Refresh();
                            break;
                        }
                        else if (this.ColorPicker.DisplayType == DisplayType.CommonColor)         // 常用颜色
                        {
                            // 【主题颜色的最后一个颜色框是按钮框】这里有个按钮需要单独做逻辑的处理
                            ColorPlateBase = new CustomColor(this);
                            this.ColorPicker.MoreBtnClickEvent();       // 通知ColorPicker已经点击了选择更多颜色
                            this.Refresh();
                            break;
                        }
                    }
                   

                    this.ColorPicker.ColorValue = ColorPlateBase.GetColorValue(i);
                    this.ColorPicker.Refresh();
                    this.Visible = false;
                    this.ColorPicker.SelectedColorEvent();          // 通知ColorPicker已经选择了颜色
                    this.Dispose();         // 每次的隐藏都是释放资源
                    break;
                }
            }
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            if (ColorPlateBase.GetType() == typeof(CustomColor))
            {
                ((CustomColor)ColorPlateBase).MouseUp(e);
                return;
            }
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            if (ColorPlateBase.GetType() == typeof(CustomColor))
            {
                ((CustomColor)ColorPlateBase).MouseDown(e);
                return;
            }
        }

        protected override void OnKeyUp(KeyEventArgs e)
        {
            if (ColorPlateBase.GetType() == typeof(CustomColor))
            {
                ((CustomColor)ColorPlateBase).KeyUp(e);
                return;
            }
        }

        #endregion

        #region ===窗口大小改变===



        protected override void OnSizeChanged(EventArgs e)
        {
            ColorPlateBase?.InitCalculate();
            this.Refresh();
        }

        #endregion

        protected override void OnLostFocus(EventArgs e)
        {
            if (this.IsDisposed == false)
            {
                this.Dispose();
            }
            
        }

    }

4. 代码粘贴貌似有点多了,长度太长了

就不粘贴了,后面我把代码上传了,给下载链接。

五、下载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值