自己繪制的滑塊條


  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

 

感覺這個控件如果要擴展的話,就拓展多一個垂直滑動,或者可以提供自定義滑塊。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM