winform自定义拖动条-横向

代码参考 https://blog.csdn.net/qq_33212020/article/details/53447135

 

 

//自定义控件:垂直滚动条
//作者:Sunday若雪   时间:2016年12月1日
//控件介绍:无上下箭头 无右键菜单 滑道和滑块颜色可调 滑块大小可调
//SliderWidthPercent(滑块宽度与控件宽度的比例):改变值为0-1之间的浮点数
//SliderHeight(滑块长度): SliderHeight的最短长度也有限制 为了保证滑块显示美观   SliderHeight最短为Wdith(控件宽度)
//Wdith(控件宽度):Wdith的设定的最小宽度为2 最大宽度为100  太大宽度也没什么用
//Height(控件长度):注意  由于MaxValue固定值为100 当控件可滑动部分长度小于100像素时为了保证算法运行正常 Height(控件长度)会随着SliderHeight的增大而变大

/*使用注意事项:必须开启SetProcessDPIAware函数,防止UI自动放大*/

/*特别说明 由于调试的时候调试器时刻在监视程序运行 或者说是由调试器发送执行指令使程序运行 程序运行速度
 * 会大幅度下降 导致控件重绘速度变慢 所以如果调试时滑动滑块发卡 那么程序脱离调试器一般就不会发卡了*/

using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;

namespace StockHelper.Scripts.Style
{
    internal class SundayRXScrollBarX : UserControl
    {
        //标志性变量*****************************************************************
        //
        protected bool MouseDownSliderFlag = false;//鼠标按下滑块标志
        protected bool MouseOverSliderFlag = false;//鼠标在滑块上方标志
        protected bool MouseDownOverSliderFlag = false;//鼠标按下滑块并在滑块上方移动标志

        //小范围使用的全局变量*******************************************************
        //
        protected int DIstance;//鼠标按下的位置与滑块顶端的距离

        protected int LastSliderPointX;//SliderPointY刷新之前的值 每次在刷新SliderPointY之前都要刷新该值

        //大范围使用的全局变量********************************************************
        //

        /*必须注意这些大范围使用的全局变量之间的关联关系 
         * 任何一个该变量的组成变量的改动都要重新计算这个变量的值*/

        protected int SliderPointX;//Width  SliderHightPercent_
        protected int SliderPointY;   //Value  Heigth  SliderWidth_
        protected int SliderHight; //Width   SliderHightPercent_
        protected Point MouseDownPoint;
        protected Point MousePoint;

        //大范围使用的方法*******************************************************
        //一些变量的值的更新方法
        protected void GetSliderPointX()//作为更新SliderPointX的值的方法
        {
            if (MouseDownOverSliderFlag == false)//当使用鼠标拖动使得Value改变时不要用再用Value计算SliderPointY
            {
                LastSliderPointX = SliderPointX;
                //计算出准确位置的浮点数
                float WantSliberPointX = Value_ * ((float)(this.Width - SliderWidth_) / 100);
                //取这个浮点数的左右整数
                int WantSliberPointY_Up = (int)WantSliberPointX;
                int WantSliberPointY_Down = WantSliberPointY_Up + 1;
                //用这两个整数假设作为当前滑块位置Y坐标,分别进行反计算出Value
                float WantSliberPointY_Up_FloatValue = WantSliberPointY_Up / ((float)(Width - SliderWidth_) / 100);
                float WantSliberPointY_Down_FloatValue = WantSliberPointY_Down / ((float)(Width - SliderWidth_) / 100);

                int WantSliberPointY_Up_IntValue = (int)WantSliberPointY_Up_FloatValue;
                int WantSliberPointY_Down_IntValue = (int)WantSliberPointY_Down_FloatValue;

                if (WantSliberPointY_Up_FloatValue > WantSliberPointY_Up_IntValue)
                {
                    WantSliberPointY_Up_IntValue++;
                }
                if (WantSliberPointY_Down_FloatValue > WantSliberPointY_Down_IntValue)
                {
                    WantSliberPointY_Down_IntValue++;
                }

                //判断两个假设Value值哪个是Value,给SliderPointY赋值

                if (Value_ == WantSliberPointY_Up_IntValue)
                {
                    SliderPointX = WantSliberPointY_Up;
                }
                else
                {
                    SliderPointX = WantSliberPointY_Down;
                }
            }
        }
       

        protected void GetSliderPointY()//作为更新SliderPointY的值的方法
        {
            if (SliderHightPercent_ == 1)
            {
                SliderPointY = Height;
            }
            else
            {
                SliderPointY = (int)(Height * (1 - SliderHightPercent_) / 2) + 1;
            }
        }

        protected void GetSliderHight()//作为更新SliderWidth的值的方法
        {
            if (SliderHightPercent_ == 1)//由于浮点数计算的误差 对于SliderWidthPercent=1的情况进行特殊处理
            {
                SliderHight = 0;
            }
            else                                          //普通情况的浮点数计算
            {
                SliderHight = (int)(Height * SliderHightPercent_) - 1;
            }
        }

        protected void GetValue()//作为更新Value的值的方法
        {
            float SliderPointY_FloatValue = SliderPointX / ((float)(Width - SliderWidth_) / 100);

            int SliderPointY_IntValue = (int)SliderPointY_FloatValue;
            if (SliderPointY_FloatValue > SliderPointY_IntValue)
            {
                SliderPointY_IntValue++;
            }
            Value = SliderPointY_IntValue;
        }

        protected void GetMousePoint()//作为更新MousePoint的值的方法
        {
            MousePoint = PointToClient(Cursor.Position);
        }

        protected void GetMouseDownPoint()//作为更新MouseDownPoint的值的方法
        {
            MouseDownPoint = PointToClient(Cursor.Position);
        }

        //判断鼠标所在位置方法
        protected bool IsMouseOverSlider()//判断鼠标是否在滑块上方
        {
            GetMousePoint();

            if (isProgress && MousePoint.Y >= SliderPointY && MousePoint.Y <= SliderPointY + SliderHight && MousePoint.X <= SliderPointX + SliderWidth_) {
                return true;
            }
            else if (MousePoint.Y >= SliderPointY && MousePoint.Y <= SliderPointY + SliderHight && MousePoint.X >= SliderPointX && MousePoint.X <= SliderPointX +  SliderWidth_)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        protected bool IsMouseOverBottom()//判断鼠标是否在滑道上
        {
            GetMousePoint();
            if (MousePoint.X < SliderPointX || MousePoint.X > SliderPointX + SliderHight)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        protected bool IsMouseOverControlEdge()//判断鼠标是否处于控件边缘部分
        {
            GetMousePoint();
            if (MousePoint.X == 0 || MousePoint.X == Width - 1 || MousePoint.Y == 0 || MousePoint.Y == Height - 1)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        //小范围使用的方法*************************************************************
        //

        protected void OnMouseOverSliderEvent()//鼠标在滑块上方悬浮时的事件
        {
            if (IsMouseOverSlider())
            {
                MouseOverSliderFlag = true;
            }
            else
            {
                MouseOverSliderFlag = false;
            }
            if (IsMouseOverControlEdge())
            {
                MouseOverSliderFlag = false;
            }
            if (!isProgress)
                Invalidate(new Region(new RectangleF(new Point(SliderPointX, SliderPointY), new Size(SliderWidth_, SliderHight))));
            else
                Invalidate(new Region(new RectangleF(new Point(0, SliderPointY), new Size(SliderPointX + SliderWidth_, SliderHight))));

        }

        //窗体设计器所添加或重写的变量******************************************************
        //

        /*设计器变量和内部变量使用规则:读数据使用内部变量(变量名带_的)
         * 写数据使用设计器变量*/
        /*直接给这些内部变量赋值相当于给了控件属性的初始值*/
        protected Color BottomColor_ = Color.FromArgb(62, 62, 66);
        protected double SliderHightPercent_ = 0.5;
        protected Color SliderColor_ = Color.FromArgb(104, 104, 104);
        protected int SliderWidth_ = 100;
        protected Color MouseDownSliderColor_ = Color.FromArgb(239, 235, 239);
        protected Color MouseOverSliderColor_ = Color.FromArgb(158, 158, 158);
        protected int Value_ = 0;
        protected int SmallChange_ = 1;

        /*让变量显示在设计器中 连接设计器变量和内部变量  更改这两个变量的任
         * 何一个另一个都会被更改并触发Set中的代码  */
        [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("外观"), Description("滑道颜色")]
        public Color BottomColor
        {
            set/*在内部变量被赋值之前设计器变量还没有被更改*/
            {/*无论更改设计器变量 还是更改内部变量 都是先将要更改值的传递给value*/

                //输入安全性效验代码 对value的值进行操作

                BottomColor_ = value;//把value值赋给BottomColor_ 

                //对组成变量含有该变量的关联变量进行值的更新

                Invalidate();                 //重绘控件

                //处理与该变量相关的事件

            }
            get { return BottomColor_; }//把BottomColor_值赋给BottomColor
        }

        [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("外观"), Description("滑块宽度相对于控件宽度的百分比 范围0-1")]
        public double SliderWidthPercent
        {
            set
            {
                if (value > 1)
                {
                    SliderHightPercent_ = 1;
                }
                else if (value < 0)
                {
                    SliderHightPercent_ = 0;
                }
                else
                {
                    SliderHightPercent_ = value;
                }
                //处理关联变量SliderPointX
                GetSliderPointX();
                //处理关联变量SliderWidth
                GetSliderHight();

                Invalidate();
            }
            get { return SliderHightPercent_; }
        }

        [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("外观"), Description("滑块的颜色")]
        public Color SliderColor
        {
            set
            {
                SliderColor_ = value;
                Invalidate();
            }
            get { return SliderColor_; }
        }

        [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("外观"), Description("当指针按下滑块时滑块的颜色")]
        public Color MouseDownSliderColor
        {
            set
            {
                MouseDownSliderColor_ = value;
                Invalidate();
            }
            get { return MouseDownSliderColor_; }
        }

        [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("外观"), Description("进度条")]
        public bool IsProgress
        {
            set{ isProgress = value; }
            get { return isProgress; }
        }
        public bool isProgress = false;



        [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("外观"), Description("当指针悬浮于滑块上时滑块的颜色")]
        public Color MouseOverSliderColor
        {
            set
            {
                MouseOverSliderColor_ = value;
                Invalidate();
            }
            get { return MouseOverSliderColor_; }
        }

        [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("行为"), Description("滚动条当前值  范围0-100")]
        public int Value
        {
            set
            {
                // 传入值合法性效验
                if (value > 100)
                {
                    value = 100;
                }
                else if (value < 0)
                {
                    value = 0;
                }
                //赋值
                Value_ = value;
                //处理关联变量SliderPointY
                GetSliderPointY();
                //重绘控件
                /*重绘控件必须要注意重绘控件所需的时间 只重绘改变的区域 不改变的不重绘*/
                if (SliderPointX - LastSliderPointX > 0)
                {
                    Invalidate(new Region(new RectangleF(new Point(LastSliderPointX-1, SliderPointY), new Size(SliderPointX + SliderWidth_ - LastSliderPointX + 2 , SliderHight))));
                }
                else if (SliderPointX - LastSliderPointX < 0)
                {
                    //由于存在向上滑动时滑块的上半圆会先消失一次的BUG 所以我改成了从顶部 到上一次滑块底边位置全部重画 如果发生卡顿 请更改绘制区域 减小重绘时间
                    Invalidate(new Region(new RectangleF(new Point(0, SliderPointY), new Size(LastSliderPointX + SliderWidth_, SliderHight))));
                }
                //处理事件ValueChanged
                ValueChanged?.Invoke(this, new EventArgs());
                //处理事件Scroll
                base.OnScroll(new ScrollEventArgs(ScrollEventType.ThumbPosition, Value_));
            }
            get { return Value_; }
        }

        [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("外观"), Description("滚动条长度 ")]
        public int SliderWidth
        {
            set
            {

                SliderWidth_ = value;
                //处理关联变量SliderPointY
                GetSliderPointX();

                Invalidate();
            }
            get { return SliderWidth_; }
        }

        [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("行为"), Description("滑轮滚动时的Value的改变值 ")]
        public int SmallChange
        {
            set
            {
                if (value < 0)
                {
                    value = SmallChange;
                }
                SmallChange_ = value;
            }
            get
            {
                return SmallChange_;
            }
        }

        //窗体设计器所废除的变量******************************************************
        //

        /*重写继承类中的变量或函数要用override关键字 并且这个变量或函数应当允许被重写*/
        /*设置Browsable(false) 设计器中将不再显示该变量 由于重写了变量改变时所运行的代码
         * 与该变量任何相关的事件都将消失*/
        [EditorBrowsable(EditorBrowsableState.Always), Browsable(false)]
        public override bool AutoScroll { set; get; }

        [EditorBrowsable(EditorBrowsableState.Always), Browsable(false)]
        public override bool AutoSize { set; get; }

        [EditorBrowsable(EditorBrowsableState.Always), Browsable(false)]
        public override Size MaximumSize { set; get; }

        [EditorBrowsable(EditorBrowsableState.Always), Browsable(false)]
        public override Size MinimumSize { set; get; }

        [EditorBrowsable(EditorBrowsableState.Always), Browsable(false)]
        public override Color BackColor { set; get; }

        [EditorBrowsable(EditorBrowsableState.Always), Browsable(false)]
        public override Font Font { get { return new Font("微软雅黑", 1); } }//这里好像必须要给个返回值 否则会提示该控件没有实例化

        [EditorBrowsable(EditorBrowsableState.Always), Browsable(false)]
        public override Color ForeColor { set; get; }

        //窗体设计器所添加或重写的事件*******************************
        //

        [EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DefaultValue(false), Category("操作"), Description("当Value值改变时发生")]
        public event EventHandler ValueChanged = null;


        public SundayRXScrollBarX()
        {
            SetStyle(ControlStyles.ResizeRedraw, true);//当控件大小改变时自动重绘           
            SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.DoubleBuffer, true);//开启双缓冲  防止重绘发生的闪烁
            this.Size = new System.Drawing.Size(150, 21);//这个大小设置是为了能够在工具箱添加控件的时候让控件重绘一次 显示正确
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            //处理关联变量SliderPointY
            GetSliderPointY();
            //处理关联变量SliderWidth
            GetSliderHight();
            //处理关联变量SliderPointX
            GetSliderPointX();

            base.OnSizeChanged(e);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            //设置绘制质量为最低 为了保证滑块在滑动时显示流畅

            e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Default;

            //绘制底色 * *****************************************************************************

            SolidBrush Bottom_SolidBrush = new SolidBrush(BottomColor_);
            Rectangle Bottom_Rc = new Rectangle(0, 0, Width, Height);
            e.Graphics.FillRectangle(Bottom_SolidBrush, Bottom_Rc);
            Bottom_SolidBrush.Dispose();

            //绘制滑块******************************************************************************
            SolidBrush Slider_SolidBrush = new SolidBrush(SliderColor_);
            if (MouseDownSliderFlag)//选择画笔颜色时被按下的优先级比悬浮于上的优先级高
            {
                Slider_SolidBrush = new SolidBrush(MouseDownSliderColor_);
            }
            else
            {
                if (MouseOverSliderFlag)
                {
                    Slider_SolidBrush = new SolidBrush(MouseOverSliderColor_);
                }
            }
            Rectangle Slider_Rc;
            if (!isProgress)
            {
                //绘制滑块的上半圆部分
                Slider_Rc = new Rectangle(SliderPointX - 1, SliderPointY - 1, SliderHight + 1, SliderHight + 1);
                e.Graphics.FillPie(Slider_SolidBrush, Slider_Rc, -90, -180);

                //绘制滑块的矩形长条部分
                e.Graphics.FillRectangle(Slider_SolidBrush, SliderPointX + (float)SliderHight / 2 - 1, (float)SliderHight / 2 + 1, SliderWidth_ - SliderHight, SliderHight);
            }
            else {
                e.Graphics.FillRectangle(Slider_SolidBrush, 0, (float)SliderHight / 2 + 1, SliderPointX + SliderWidth_/2 + 1, SliderHight);
            }


            //绘制滑块的下半圆部分
            Slider_Rc = new Rectangle(SliderPointX + SliderWidth_ - SliderHight - 1, SliderPointY - 1, SliderHight, SliderHight + 1);
            e.Graphics.FillPie(Slider_SolidBrush, Slider_Rc, 90, -180);

            //释放画笔资源
            Slider_SolidBrush.Dispose();
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                GetMouseDownPoint();//取得相对于控件的鼠标按下位置
                
                //判断是否单击在了滑道上
                if (isProgress || IsMouseOverBottom())
                {
                    GetMouseDownPoint();
                    int WantSliderPointY = MouseDownPoint.X - SliderWidth_ / 2;
                    if (WantSliderPointY < 0)
                    {
                        WantSliderPointY = 0;
                    }
                    else if (WantSliderPointY + SliderWidth_ / 2 > this.Width)
                    {
                        WantSliderPointY = this.Width - (SliderWidth_ / 2);
                    }
                    LastSliderPointX = SliderPointX;
                    SliderPointX = WantSliderPointY;
                    GetValue();
                    Invalidate();//再刷一下 不然不会变
                }
                //判断是否单击在了滑块上(具体看滚动条的形状与大小务必自行更改代码适应)
                else if (IsMouseOverSlider())
                {
                    DIstance = MouseDownPoint.X - SliderPointX;//得到鼠标按下是与滑块顶部的距离
                    //更改滑块颜色为高亮 重绘控件
                    if (!isProgress)
                        Invalidate(new Region(new RectangleF(new Point(SliderPointX, SliderPointY), new Size(SliderWidth_, SliderHight))));
                    else
                        Invalidate(new Region(new RectangleF(new Point(0, SliderPointY), new Size(SliderPointX + SliderWidth_, SliderHight))));
                }

                MouseDownSliderFlag = true;//滑块被按下标志使能
            }

            //判断是否单击在了向下箭头上

            base.OnMouseDown(e);
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (MouseDownSliderFlag)
            {
                MouseDownOverSliderFlag = true;

                GetMousePoint();
                LastSliderPointX = SliderPointX;
                SliderPointX = MousePoint.X - DIstance;
                if (SliderPointX < 0)
                {
                    SliderPointX = 0;
                }
                else if (SliderPointX > Width - SliderWidth_)
                {
                    SliderPointX = Width - SliderWidth_;
                }
                //处理关联变量Vlaue
                GetValue();

                //关闭鼠标按下并移动标志
                MouseDownOverSliderFlag = false;
            }
            else
            {
                OnMouseOverSliderEvent();
            }

            base.OnMouseMove(e);
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            if (MouseDownSliderFlag)
            {
                MouseDownOverSliderFlag = false;
            }
            if (!isProgress)
                Invalidate(new Region(new RectangleF(new Point(SliderPointX, SliderPointY), new Size(SliderWidth_, SliderHight))));
            else
                Invalidate(new Region(new RectangleF(new Point(0, SliderPointY), new Size(SliderPointX + SliderWidth_ , SliderHight))));


            MouseDownSliderFlag = false;
            base.OnMouseUp(e);
        }

        protected override void OnMouseWheel(MouseEventArgs e)
        {
            //计算Value值
            if (e.Delta > 0)
            {
                if (Value - SmallChange_ < 0)
                {
                    Value = 0;
                }
                else
                {
                    Value = Value - SmallChange_;
                }
            }
            else
            {
                if (Value + SmallChange_ > 100)
                {
                    Value = 100;
                }
                else
                {
                    Value = Value + SmallChange_;
                }
            }
            //处理当鼠标位于滑块上时的事件
            OnMouseOverSliderEvent();
        }
        
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值