• 自己绘制的滑块条


      Trackbar见了很多种,每种播放器的都有它自己风格的Trackbar,鄙人最近在写一个属于自己的播放器,但是不想使用VS工具箱里面的那个Trackbar,于是上网看了一下资料,自己也模仿地写了一个。

      其实写这个控件,关键就是用GDI+来绘图,对于这个Trackbar控件必要的属性和行为(包括方法、事件),一个简单的Trackbar就能做出来了。感觉这个就是一个GDI+章节的练习吧。

      我写的这个Trackbar是继承Control类的,不是TrackBar,也不是UserControl类,又不是ScrollableControl类。

    • Trackbar有以下外放的属性
    • MinValue:Trackerbar标尺的最小值
    • MaxValue:Trackerbar标尺的最大值
    • Value:Trackerbar滑块的当前值
    • FillColor:标尺上最小值到当前值的颜色
    • EmptyColor:标尺上当前值到最大值间的颜色
    • Shape:滑块的形状,目前只有两种,圆形和矩形

    接下来就展示利用GDI+绘制整个Trackbar的方法

     1         protected override void OnPaint(PaintEventArgs e)
     2         {
     3             using (Bitmap bit=new Bitmap(this.Width,this.Height))
     4             {
     5                 using (Graphics g=Graphics.FromImage(bit))
     6                 {
     7                     using (SolidBrush emptyBrush=new SolidBrush(EmptyColor))
     8                     {
     9                         g.FillRectangle(emptyBrush, BordHeight, 2 + BordHeight / 2f, BorderLength, BordHeight);
    10                     }
    11 
    12                     using (SolidBrush valueBrush=new SolidBrush(FillColor))
    13                     {
    14                         g.FillRectangle(valueBrush, BordHeight+1f, 2 + BordHeight / 2f+1f, ValueX-2,BordHeight-2 );
    15                         switch (Shape)
    16                         {
    17                             case TrackShape.Circle: DrawCircleTrack(g, valueBrush); break;
    18                             case TrackShape.Rectanles: DrawRectangles(g, valueBrush); break;
    19                         }
    20                     }
    21                 }
    22                 e.Graphics.DrawImage(bit, 0, 0);
    23             }
    24         }
    25     

    此处是重写了Control类的OnPaint方法,每当控件重绘的时候就会调用这个方法了,整个绘制的流程大致就这样

    1. 绘制整条标尺并填充EmptyColor;(第9行)
    2. 把标尺起点到当前值间的标尺颜色涂成FillColor;(第14行)
    3. 根据滑块的形状在当前值的位置绘制滑块(17行和18行)

      其中标尺的矩形高度是定了是3,宽度就是与整个控件的宽度相差6,也就是控件左右边距各留3个像素的补白。

      还定义了两个方法分别绘制两种滑块

    圆形滑块的半径就与标尺的高度相等,圆心的位置就在当前值的刻度线的中点。

            protected void DrawCircleTrack(Graphics g,SolidBrush brush)
            {
                using (Pen emptyPen = new Pen(EmptyColor))
                {
                    g.FillEllipse(brush, ValueX, 2, 2 * BordHeight, 2 * BordHeight);
                    g.DrawEllipse(emptyPen, ValueX, 2, 2 * BordHeight, 2 * BordHeight);
                }
            }

    矩形滑块的宽度与标尺的高度相等,滑块的高度刚好是标尺高度的两倍,矩形滑块的中心是跟当前值的刻度线的中点重合。

            protected void DrawRectangles(Graphics g,SolidBrush brush)
            {
                using (Pen emptyPen = new Pen(EmptyColor))
                {
                    g.FillRectangle(brush, ValueX + BordHeight / 2, 2, BordHeight, 2 * BordHeight);
                    g.DrawRectangle(emptyPen, ValueX + BordHeight / 2, 2, BordHeight, 2 * BordHeight);
                }
            }

    控件还重写了Control基类的几个方法,以待控件触发了某些事件时调用,目的就是实现滑块滑动和跳动的效果。

            protected override void OnMouseClick(MouseEventArgs e)
            {
                base.OnMouseClick(e);
                if (e.Button != System.Windows.Forms.MouseButtons.Left) return;
                int tempValue = LocationX2Value(e.X);
                if (tempValue > MaxValue) Value = MaxValue;
                else if (tempValue < MinValue) Value = MinValue;
                else Value = tempValue;
            }

    这个是当鼠标单击控件时执行的方法,根据鼠标点击的位置,通过数学上一次函数计算出相应的当前值。以实现滑块跳动到当前鼠标点击的刻度上。

            protected override void OnMouseMove(MouseEventArgs e)
            {
                base.OnMouseMove(e);
                if (e.Button != System.Windows.Forms.MouseButtons.Left) return;
                int tempValue = LocationX2Value(e.X);
                if (tempValue > MaxValue) Value = MaxValue;
                else if (tempValue < MinValue) Value = MinValue;
                else Value = tempValue;
            }

    这个是鼠标上的某个键在控件上拖动时执行的方法,跟上面的原理一样,实现滑块滑动的效果。

            protected override void OnResize(EventArgs e)
            {
                base.OnResize(e);
                this.Refresh();
            }

    这个是控件的大小发生变化时执行,为了让控件重绘。

    我这里还模仿VS的Trackbar的Scroll事件那样,外放了一个Scroll事件,实际上触发的条件就是当前值发生变化。因为在滑块滑动的时候本质上就是当前值在变化

            public event EventHandler Scroll = null;
            public virtual void OnScroll()
            {
                if (Scroll != null)
                {
                    Scroll(this, new EventArgs());
                }
            }

    这里没有去继承ScrollableControl类,去重写它的OnScroll方法。主要是没有用上它的OldValue和NewValue。

    控件效果图如下

    整个控件的完整代码如下

      1     public class PlayerTrackBar : Control
      2     {
      3         protected const int BordHeight = 6;
      4 
      5         public PlayerTrackBar()
      6         {
      7             this.MinValue = 0;
      8             this.MaxValue = 100;
      9             this.Value = 0;
     10             this.Width = 200;
     11             this.DoubleBuffered = true;
     12         }
     13 
     14         private int minValue, maxValue, currValue;
     15 
     16         [ Description("最小值"),Category("")]
     17         public int MinValue
     18         {
     19             get { return minValue; }
     20             set {
     21                 if (value > MaxValue) return;
     22                 minValue = value;
     23                 this.Refresh();
     24             }
     25         }
     26 
     27         [Description("最大值"), Category("")]
     28         public int MaxValue
     29         {
     30             get { return maxValue; }
     31             set 
     32             {
     33                 if (value < MinValue) return;
     34                 maxValue = value;
     35                 this.Refresh();
     36             }
     37         }
     38 
     39         [Description("当前值"), Category("")]
     40         public int Value
     41         {
     42             get { return currValue; }
     43             set 
     44             {
     45                 int preValue = currValue;
     46                 if (value > MaxValue) currValue = MaxValue;
     47                 else if (value < MinValue) currValue = MinValue;
     48                 else currValue = value;
     49                 this.Refresh();
     50                 if (preValue != currValue) OnScroll();
     51             }
     52         }
     53 
     54         private Color fillColor= Color.White;
     55         [Description("有值部分颜色"), Category("外观")]
     56         public Color FillColor
     57         {
     58             get { return fillColor; }
     59             set { fillColor = value; }
     60         }
     61 
     62         private Color emptyColor = Color.FromArgb(135, 124, 124);
     63         [Description("无值部分颜色"), Category("外观")]
     64         public Color EmptyColor
     65         {
     66             get { return emptyColor; }
     67             set { emptyColor = value; }
     68         }
     69 
     70         [Description("滑块形状"), Category("外观")]
     71         public TrackShape Shape { get; set; }
     72 
     73         protected float ValueX
     74         {
     75             get 
     76             {
     77                 return (Value - MinValue) / (float)(MaxValue - MinValue) * BorderLength;
     78             }
     79         }
     80 
     81         protected int BorderLength
     82         {
     83             get
     84             {
     85                 return this.Width - BordHeight*2;
     86             }
     87         }
     88 
     89         protected void DrawCircleTrack(Graphics g,SolidBrush brush)
     90         {
     91             using (Pen emptyPen = new Pen(EmptyColor))
     92             {
     93                 g.FillEllipse(brush, ValueX, 2, 2 * BordHeight, 2 * BordHeight);
     94                 g.DrawEllipse(emptyPen, ValueX, 2, 2 * BordHeight, 2 * BordHeight);
     95             }
     96         }
     97 
     98         protected void DrawRectangles(Graphics g,SolidBrush brush)
     99         {
    100             using (Pen emptyPen = new Pen(EmptyColor))
    101             {
    102                 g.FillRectangle(brush, ValueX + BordHeight / 2, 2, BordHeight, 2 * BordHeight);
    103                 g.DrawRectangle(emptyPen, ValueX + BordHeight / 2, 2, BordHeight, 2 * BordHeight);
    104             }
    105         }
    106 
    107         /// <summary>
    108         /// 通过鼠标当前位置计算出进度值
    109         /// </summary>
    110         /// <param name="x">鼠标当前位置</param>
    111         /// <returns></returns>
    112         protected int LocationX2Value(int x)
    113         {
    114             return (int)((MaxValue - MinValue) / (float)BorderLength * (x - BordHeight) + MinValue);
    115         }
    116 
    117         protected override void OnPaint(PaintEventArgs e)
    118         {
    119             using (Bitmap bit=new Bitmap(this.Width,this.Height))
    120             {
    121                 using (Graphics g=Graphics.FromImage(bit))
    122                 {
    123                     using (SolidBrush emptyBrush=new SolidBrush(EmptyColor))
    124                     {
    125                         g.FillRectangle(emptyBrush, BordHeight, 2 + BordHeight / 2f, BorderLength, BordHeight);
    126                     }
    127 
    128                     using (SolidBrush valueBrush=new SolidBrush(FillColor))
    129                     {
    130                         g.FillRectangle(valueBrush, BordHeight+1f, 2 + BordHeight / 2f+1f, ValueX-2,BordHeight-2 );
    131                         switch (Shape)
    132                         {
    133                             case TrackShape.Circle: DrawCircleTrack(g, valueBrush); break;
    134                             case TrackShape.Rectanles: DrawRectangles(g, valueBrush); break;
    135                         }
    136                     }
    137                 }
    138                 e.Graphics.DrawImage(bit, 0, 0);
    139             }
    140         }
    141 
    142         protected override void OnMouseClick(MouseEventArgs e)
    143         {
    144             base.OnMouseClick(e);
    145             if (e.Button != System.Windows.Forms.MouseButtons.Left) return;
    146             int tempValue = LocationX2Value(e.X);
    147             if (tempValue > MaxValue) Value = MaxValue;
    148             else if (tempValue < MinValue) Value = MinValue;
    149             else Value = tempValue;
    150         }
    151 
    152         protected override void OnMouseMove(MouseEventArgs e)
    153         {
    154             base.OnMouseMove(e);
    155             if (e.Button != System.Windows.Forms.MouseButtons.Left) return;
    156             int tempValue = LocationX2Value(e.X);
    157             if (tempValue > MaxValue) Value = MaxValue;
    158             else if (tempValue < MinValue) Value = MinValue;
    159             else Value = tempValue;
    160         }
    161 
    162         [Description("当值变化后触发的事件"), Category("")]
    163         public event EventHandler Scroll = null;
    164         public virtual void OnScroll()
    165         {
    166             if (Scroll != null)
    167             {
    168                 Scroll(this, new EventArgs());
    169             }
    170         }
    171 
    172         protected override void OnResize(EventArgs e)
    173         {
    174             base.OnResize(e);
    175             this.Refresh();
    176         }
    177 
    178         public enum TrackShape
    179         {
    180             Circle,
    181             Rectanles
    182         }
    183     }
    PlayerTrackBar

    感觉这个控件如果要扩展的话,就拓展多一个垂直滑动,或者可以提供自定义滑块。

  • 相关阅读:
    HttpClient入门三
    Centos常用命令之:压缩与解压缩
    Centos常用命令之:搜索
    Centos常用命令之:ln
    Centos常用命令之:VI
    HttpClient入门二
    NX二次开发-UFUN确定两个向量在指定的公差内是否相等(二维向量)UF_VEC2_is_equal
    NX二次开发-UFUN确定两个向量在指定的公差内是否相等(三维向量)UF_VEC3_is_equal
    NX二次开发-NXOPEN C#UF创建块theUfSession.Modl.CreateBlock1
    NX二次开发-NXOpen C# UF函数例子目录【更新日期2020.7.21】
  • 原文地址:https://www.cnblogs.com/HopeGi/p/3281601.html
Copyright © 2020-2023  润新知