农民 发表于 2022-6-20 10:42:25

WinForm Custom(二) 滑块控件

https://img2022.cnblogs.com/blog/1735495/202206/1735495-20220610175633600-1252528070.png
public class ZhmSlider : Control
    {
      private Rectangle foreRect;
      private Rectangle backRect;
      private Rectangle setRect;

      private Color backgroundColor = Color.White;
      private Color foregroundColor = Color.Gray;
      private Color setRectColor = Color.Black;//滑块颜色
      private Color fontColor = Color.Black;
      private Color borderColor = Color.Black;

      private int maximum = 100; //进度条最大值
      private int minimum = 0;//进度条最小值
      private double _value = 0;//进度条当前值

      private bool showPercent; //当前进度百分比
      private float fontSize = 9;//
      private FontFamily _fontFamily = new FontFamily("Segoe UI");

      private Point originPoint;
      private Point originsetRectPoint;
      private bool setRectDown = false;

      public ZhmSlider()
      {
            // 避免重绘时窗口闪烁
            this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.UserPaint, true);

            this.MouseDown += ZhmSlider_MouseDown;
            this.MouseMove += ZhmSlider_MouseMove;
            this.MouseUp += ZhmSlider_MouseUp;
      }

      private void ZhmSlider_MouseUp(object sender, MouseEventArgs e)
      {
            setRectDown = false;
      }

      private void ZhmSlider_MouseMove(object sender, MouseEventArgs e)
      {
            if (setRectDown)
            {
                int dd = e.Location.X - originPoint.X;

                double percent = (double)(originsetRectPoint.X + dd - this.backRect.X) / (this.backRect.Width - this.backRect.Height);
                if (percent < 0)
                {
                  this.Value = minimum;
                  this.foreRect.Width = 0;
                  this.setRect.X = backRect.X;
                }
                else if (percent > 1)
                {
                  this.Value = maximum;
                  this.foreRect.Width = this.backRect.Width;
                  this.setRect.X = backRect.X + backRect.Width - backRect.Height;
                }
                else
                {
                  this.Value = percent * maximum;
                  this.foreRect.Width = (int)(percent * this.backRect.Width);
                  this.setRect.X = originsetRectPoint.X + dd;
                }
                Invalidate();
            }
      }

      private void ZhmSlider_MouseDown(object sender, MouseEventArgs e)
      {
            if (setRect.Contains(e.Location))
            {
                this.originPoint = e.Location;
                originsetRectPoint = this.setRect.Location;
                this.setRectDown = true;
            }
      }

      
      public bool ShowPercentTag
      {
            get { return showPercent; }
            set
            {
                showPercent = value;
                Invalidate();
            }
      }
      
      public int Maximum
      {
            get { return maximum; }
            set
            {
                maximum = value;
                Invalidate();
            }
      }
      
      public int Minimum
      {
            get { return minimum; }
            set
            {
                minimum = value;
                Invalidate();
            }
      }

      
      public float FontSize
      {
            get { return fontSize; }
            set
            {
                this.fontSize = value;
                Invalidate();
            }
      }
      
      public FontFamily FontFamily
      {
            get { return _fontFamily; }
            set
            {
                this._fontFamily = value;
                Invalidate();
            }
      }

      
      public Color BackgroundColor
      {
            get { return backgroundColor; }
            set
            {
                this.backgroundColor = value;
                Invalidate();
            }
      }
      
      public Color ForegroundColor
      {
            get { return foregroundColor; }
            set
            {
                this.foregroundColor = value;
                Invalidate();
            }
      }
      
      public Color SetRectColor
      {
            get { return setRectColor; }
            set
            {
                this.setRectColor = value;
                Invalidate();
            }
      }
      
      public Color FontColor
      {
            get { return fontColor; }
            set
            {
                this.fontColor = value;
                Invalidate();
            }
      }

      
      public Color BorderColor
      {
            get { return borderColor; }
            set
            {
                this.borderColor = value;
                Invalidate();
            }
      }


      //确定控件的位置。 我们根据宽度和高度属性确定矩形的位置。 因为Control类也有这两个属性,所以我们在前面添加new来覆盖原来的属性
      
      public new int Width
      {
            get { return base.Width; }
            set
            {
                base.Width = value;
                foreRect.X = backRect.X = base.Width / 20;
                backRect.Width = base.Width * 9 / 10;
                foreRect.Width = (int)(_value / maximum * backRect.Width);
                setRect.X = (int)(_value / maximum * (backRect.Width - backRect.Height) + foreRect.X);

                Invalidate();
            }
      }
      
      public new int Height
      {
            get { return base.Height; }
            set
            {
                base.Height = value;
                foreRect.Height = backRect.Height = setRect.Height = setRect.Width = base.Height / 3;
                foreRect.Y = backRect.Y = setRect.Y = base.Height / 3;
                Invalidate();
            }
      }

      //值发生变化的属性。 当向事件添加外部响应函数时,事件将生效,否则OnValueChanged方法的值为空
      protected EventHandler OnValueChanged;
      public event EventHandler ValueChanged
      {
            add
            {
                if (OnValueChanged != null)
                  foreach (Delegate d in OnValueChanged.GetInvocationList())
                        if (object.ReferenceEquals(d, value)) return;
                OnValueChanged = (EventHandler)Delegate.Combine(OnValueChanged, value);
            }
            remove
            {
                OnValueChanged = (EventHandler)Delegate.Remove(OnValueChanged, value);
            }
      }

      //定义value的值。 当Value值发生变化时,重置矩形的进度,控制块的位置,并重新绘制控件(如果在value属性中修改进度条的值,请使用_value变量,在其他地方,请使Value属性 )
      
      public double Value
      {
            get { return _value; }
            set
            {
                if (_value < Minimum)
                  throw new ArgumentException("Less than minimum");
                if (_value > Maximum)
                  throw new ArgumentException("Exceeds the maximum");

                _value = value;
                foreRect.Width = (int)(_value / maximum * backRect.Width);
                setRect.X = (int)(_value / maximum * (backRect.Width - backRect.Height) + backRect.X);

                if ((_value - maximum) > 0)
                {
                  foreRect.Width = backRect.Width;
                  setRect.X = backRect.Width - backRect.Height + backRect.X;
                }

                if (OnValueChanged != null)
                  OnValueChanged(this, EventArgs.Empty);

                Invalidate();
            }
      }
      //绘制控件,重载OnPaint方法来绘制控件
      protected override void OnPaint(PaintEventArgs pe)
      {
            base.OnPaint(pe);

            DrawRect(pe.Graphics);
            DrawText(pe.Graphics);
      }

      //滑块区域
      private void DrawRect(Graphics e)
      {
            Pen pen = new Pen(this.foregroundColor);

            e.FillRectangle(new SolidBrush(this.backgroundColor), backRect);
            e.DrawRectangle(new Pen(this.borderColor), backRect);

            e.FillRectangle(new SolidBrush(this.foregroundColor), foreRect);
            e.DrawRectangle(new Pen(this.borderColor), foreRect);

            e.FillRectangle(new SolidBrush(this.setRectColor), setRect);
            e.DrawRectangle(new Pen(this.borderColor), setRect);
      }

         // 绘制文本
      private void DrawText(Graphics e)
      {
            Point point = new Point();
            point.X = this.backRect.X + this.backRect.Width * 3 / 7;
            point.Y = this.backRect.Y + this.backRect.Height / 3;

            SolidBrush brush = new SolidBrush(fontColor);
            Font font = new Font(_fontFamily, this.fontSize);
            string percent = ((int)this._value).ToString() + "%";

            //设置文本居中
            StringFormat format = new StringFormat();
            format.Alignment = StringAlignment.Center;
            format.LineAlignment = StringAlignment.Center;

            e.DrawString(percent, font, brush, backRect, format);
      }

      //在设计期间更改控件的大小时调用OnResize方法。 当您拖动边缘上的箭头来更改控件的大小时,当需要对控件进行相应更改时,可以重写此方法。如果没有重新加载,则只有在修改完成后才会更新控件。
      protected override void OnResize(EventArgs e)
      {
            base.OnResize(e);
            this.Width = Width;
            this.Height = Height;
            Invalidate();
      }
    }
来源:https://www.cnblogs.com/zhuanghamiao/archive/2022/06/13/winform-custom-slider.html
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: WinForm Custom(二) 滑块控件