自己绘制的滑块条

  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

 

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

你可能感兴趣的:(自己绘制的滑块条)