FlashTrackBar is a control that can be used to show the level or the progress of an application. It uses a gradient to visually represent progress. To download the source code for FlashTrackBar and to see an example of how it is used, see the Win Forms QuickStart.
FlashTrackBar defines the following custom properties:
AllowUserEdit
EndColor
DarkenBy
Max
Min
StartColor
ShowPercentage
ShowValue
ShowGradient
Value
FlashTrackBar defines the following members for a custom event:
valueChanged
AddOnValueChanged
OnValueChanged
RemoveOnValueChanged
Note FlashTrackBar uses the EventArgs class for event "data", becasue the value changed event does not have associated event data. Because there is no data, it is not necessary to declare a custom delegate, and the EventHandler delegate type is adequate.
FlashTrackBar overrides the following methods inherited from System.WinForms.RichControl:
OnPaint
FlashTrackBar overrides the following methods inherited from System.WinForms.Control:
OnMouseDown
OnMouseMove
OnMouseUp
OnPropertyChanged
OnResize
FlashTrackBar provides a custom Validate method that hides the Validate method inherited from Control.
The complete source code for FlashTrackBar is listed below.
[C#] namespace SampleControlPack { using System; using System.ComponentModel; using System.ComponentModel.Design; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Design; using System.WinForms; using System.Diagnostics; // // <doc> // <desc> // FlashTrackBar is a track bar that uses a gradient fill to // render the track value. // </desc> // </doc> // public class FlashTrackBar : RichControl { private const int LeftRightBorder = 10; private int value = 0; private int min = 0; private int max = 100; private bool showPercentage = false; private bool showValue = false; private bool allowUserEdit = true; private bool showGradient = true; private int dragValue = 0; private bool dragging = false; private Color startColor = Color.Red; private Color endColor = Color.LimeGreen; private EventHandler valueChanged; private Brush baseBackground = null; private Brush backgroundDim = null; private byte darkenBy = 200; // // <doc> // <desc> // Creates a new FlashTrackBar instance. // </desc> // </doc> // public FlashTrackBar() { // There are two styles on this control. The first, // Opaque,specifies that the entire contents // of the control will be painted. This avoids flicker // The second, ResizeRedraw, specifies that the control // must be redrawn whenever // the size of our control changes. // SetStyle(ControlStyles.Opaque, true); SetStyle(ControlStyles.ResizeRedraw, true); ForeColor = Color.White; BackColor = Color.Black; // Configure a default width and height. // Width = 100; Height = 30; } // // <doc> // <desc> //This property determines if the user can change the value //of the flash track bar by clicking and dragging on it. // </desc> // </doc> // [ Category("Flash"), Description("Determines if the user can change the value of the FlashTrackBar by clicking and dragging on it.") ] public bool AllowUserEdit { get { return allowUserEdit; } set { if (value != allowUserEdit) { allowUserEdit = value; if (!allowUserEdit) { Capture = false; dragging = false; } } } } // // <doc> // <desc> // This property is the end color of the bar. The end color // is the color the bar will have when the value is equal to // the Max property. // </desc> // </doc> // [ Category("Flash"), Description("The ending color of the bar.") ] public Color EndColor { get { return endColor; } set { endColor = value; if (baseBackground != null && showGradient) { baseBackground.Dispose(); baseBackground = null; } Invalidate(); } } // // <doc> // <desc> // The amount to darken the background by. The background is // painted in the same gradient as the foreground value. // This determines how dark the background will be with // respect to the foreground. // Notice that this property uses a special UI editor. // The Editor attributes informs the designer which // editor to use. // </desc> // </doc> // [ Category("Flash"), Editor(typeof(FlashTrackBarDarkenByEditor), typeof(UITypeEditor)), Description("How much to darken the background with respect to the foreground gradient.") ] public byte DarkenBy { get { return darkenBy; } set { if (value != darkenBy) { darkenBy = value; if (backgroundDim != null) { backgroundDim.Dispose(); backgroundDim = null; } Invalidate(); } } } // // <doc> // <desc> // The maximum value of the track bar. // </desc> // </doc> // [ Category("Flash"), Description("The maximum value of the track bar.") ] public int Max { get { return max; } set { if (max != value) { max = value; Invalidate(); } } } // // <doc> // <desc> // The minimum value of the track bar. // </desc> // </doc> // [ Category("Flash"), Description("The minimum value of the track bar.") ] public int Min { get { return min; } set { if (min != value) { min = value; Invalidate(); } } } // // <doc> // <desc> // The starting color of the gradient. // </desc> // </doc> // [ Category("Flash"), Description("The starting color of the track bar gradient.") ] public Color StartColor { get { return startColor; } set { startColor = value; if (baseBackground != null && showGradient) { baseBackground.Dispose(); baseBackground = null; } Invalidate(); } } // // <doc> // <desc> // Determines if the percentage should be displayed on top of the // track bar gradient. // </desc> // </doc> // [ Category("Flash"), Description("Determines if a percentage should be displayed over the track bar gradient."), RefreshProperties(RefreshProperties.Repaint) ] public bool ShowPercentage { get { return showPercentage; } set { if (value != showPercentage) { showPercentage = value; if (showPercentage) { showValue = false; } Invalidate(); } } } // // <doc> // <desc> // Determines if the actual value should be displayed on top of // the trackbar gradient. // </desc> // </doc> // [ Category("Flash"), Description("Determines if the current value should be displayed over the track bar gradient."), RefreshProperties(RefreshProperties.Repaint) ] public bool ShowValue { get { return showValue; } set { if (value != showValue) { showValue = value; if (showValue) { showPercentage = false; } Invalidate(); } } } // // <doc> // <desc> // Determines if the track bar should display a gradient // indicating the current value. // </desc> // </doc> // [ Category("Flash"), Description("Determines if the track bar should display a color gradient indicating the current value.") ] public bool ShowGradient { get { return showGradient; } set { if (value != showGradient) { showGradient = value; if (baseBackground != null) { baseBackground.Dispose(); baseBackground = null; } Invalidate(); } } } // // <doc> // <desc> // The current value of the track bar. // </desc> // </doc> // [ Category("Flash"), Editor(typeof(FlashTrackBarValueEditor), typeof(UITypeEditor)), Description("The current value of the track bar. You may enter an actual value or a percentage."), TypeConverter(typeof(FlashTrackBarValueConverter)) ] public int Value { get { if (dragging) { return dragValue; } return value; } set { if (value != this.value) { int old = this.value; this.value = value; OnValueChanged(EventArgs.Empty); Invalidate(); } } } // // <doc> // <desc> // Adds an event handler for the value changed event. This event // is raised when the value of the track bar changes. // </desc> // </doc> // public void AddOnValueChanged(EventHandler handler) { valueChanged = (EventHandler)Delegate.Combine(valueChanged, handler); } // // <doc> // <desc> // This is a custom Invalidate method. It computes the rectangle // between oldValue and newValue and invalidates just that part // to avoid flicker. // </desc> // </doc> // private void Invalidate(int oldValue, int newValue) { // First, do the position of the slider // int oldPos = (int)((float)oldValue / ((float)Max - (float)Min) * Width); int newPos = (int)((float)newValue / ((float)Max - (float)Min) * Width); Rectangle invalidRect = new Rectangle( Math.Min(oldPos, newPos), 0, Math.Abs(oldPos - newPos), Height); Invalidate(invalidRect); // If any text is changed, // invalidate that area too. // if (ShowPercentage || ShowValue) { string toDisplay = string.Empty; int displayValue = Math.Max(oldPos, newPos); if (ShowPercentage) { toDisplay = Convert.ToString((int)(displayValue * 100 / Width)) + "%"; } else if (ShowValue) { toDisplay = Convert.ToString(displayValue); } Graphics g = CreateGraphics(); SizeF textSize = g.MeasureString(toDisplay, Font.NewFont, new SizeF(0, 0)); g.Dispose(); // The + and - 1 factors here are to account for // floating point round // off errors. // invalidRect.X = (int)(((float)Width - (float)textSize.Width) / 2.0) - 1; invalidRect.Y = (int)(((float)Height - (float)textSize.Height) / 2.0) - 1; invalidRect.Width = (int)textSize.Width + 1; invalidRect.Height = (int)textSize.Height + 1; Invalidate(invalidRect); } } // // <doc> // <desc> // Override from control. Handles mouse movements if // user edit is set to true. // </desc> // </doc> // protected override void OnMouseDown(MouseEventArgs e) { base.OnMouseDown(e); if (!allowUserEdit) { return; } Capture = true; dragging = true; SetDragValue(new Point(e.X, e.Y)); } // // <doc> // <desc> // Override from control. Handle mouse movements if user edit // is set to true. // </desc> // </doc> // protected override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); if (!allowUserEdit || !dragging) { return; } SetDragValue(new Point(e.X, e.Y)); } // // <doc> // <desc> // Override from control. Handle mouse movements if user edit // is set to true. // </desc> // </doc> // protected override void OnMouseUp(MouseEventArgs e) { base.OnMouseUp(e); if (!allowUserEdit || !dragging) { return; } Capture = false; dragging = false; value = dragValue; OnValueChanged(EventArgs.Empty); } // // <doc> // <desc> // Override from control. This paints the user interface // for our control. // </desc> // </doc> // protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); // The background brush is cached for speed. // If it isn't set here, create it. if (baseBackground == null) { if (showGradient) { baseBackground = new LinearGradientBrush(new Point(0, 0), new Point(ClientSize.Width, 0),StartColor, EndColor); } else if (BackgroundImage != null) { baseBackground = new TextureBrush(BackgroundImage); } else { baseBackground = new SolidBrush(BackColor); } } // To dim the background, paint over the top of the gradient // with an alpha-blended black brush. // if (backgroundDim == null) { backgroundDim = new SolidBrush(Color.FromARGB(DarkenBy, Color.Black)); } // Calculate the location of the elements. // Rectangle toDim = ClientRectangle; float percentValue = ((float)Value / ((float)Max - (float)Min)); int nonDimLength = (int)(percentValue * (float)toDim.Width); toDim.X += nonDimLength; toDim.Width -= nonDimLength; // Compute the dimensions of the text to render, if // text is to be rendered. // string text = Text; string toDisplay = null; RectangleF textRect = new RectangleF(); if (ShowPercentage || ShowValue || text.Length > 0) { if (ShowPercentage) { toDisplay = Convert.ToString((int)(percentValue * 100f)) + "%"; } else if (ShowValue) { toDisplay = Convert.ToString(Value); } else { toDisplay = text; } SizeF textSize = e.Graphics.MeasureString(toDisplay, Font.NewFont, new SizeF(0, 0)); textRect.X = (ClientRectangle.Width - textSize.Width) / 2; textRect.Y = (ClientRectangle.Height - textSize.Height) / 2; textRect.Width = textSize.Width; textRect.Height = textSize.Height; } // Now draw the gradients and the text. // e.Graphics.FillRectangle(baseBackground, ClientRectangle); e.Graphics.FillRectangle(backgroundDim, toDim); if (toDisplay != null && toDisplay.Length > 0) { e.Graphics.Flush(); e.Graphics.DrawString(toDisplay, Font.NewFont, new SolidBrush(ForeColor), textRect); } } // // <doc> // <desc> // Override from control. Look for specific properties that have // changed and update our control. // </desc> // </doc> // protected override void OnPropertyChanged (PropertyChangedEventArgs e) { base.OnPropertyChanged(e); if (e.PropertyName.Equals("Text")) { Invalidate(); } else if (!showGradient) { if (e.PropertyName.Equals("BackColor") || e.PropertyName.Equals("BackgroundImage")) { if (baseBackground != null) { baseBackground.Dispose(); baseBackground = null; } Invalidate(); } } } // // <doc> // <desc> // Override from control. Get rid of our background // brush if resized, because it will have to be recreated // for the new size. // </desc> // </doc> // protected override void OnResize(EventArgs e) { if (baseBackground != null) { baseBackground.Dispose(); baseBackground = null; } base.OnResize(e); } // // <doc> // <desc> // The protected part of our value changed event. This is the // method to call when the value has actually changed. Deriving // controls may override this. // </desc> // </doc> // protected virtual void OnValueChanged(EventArgs e) { if (valueChanged != null) { valueChanged(this, e); } } // // <doc> // <desc> // Removes the given event handler. // </desc> // </doc> // public void RemoveOnValueChanged(EventHandler handler) { valueChanged = (EventHandler)Delegate.Remove(valueChanged, handler); } // // <doc> // <desc> // Private function that sets the Value property given the current // mouse location. // </desc> // </doc> // private void SetDragValue(Point mouseLocation) { Rectangle client = ClientRectangle; if (client.Contains(mouseLocation)) { float percentage = (float)mouseLocation.X / (float)ClientRectangle.Width; int newDragValue = (int)(percentage * (float)(max - min)); if (newDragValue != dragValue) { int old = dragValue; dragValue = newDragValue; Invalidate(old, newDragValue); } } else { if (client.Y <= mouseLocation.Y && mouseLocation.Y <= client.Y + client.Height) { if (mouseLocation.X <= client.X && mouseLocation.X > client.X - LeftRightBorder) { int newDragValue = min; if (newDragValue != dragValue) { int old = dragValue; dragValue = newDragValue; Invalidate(old, newDragValue); } } else if (mouseLocation.X >= client.X + client.Width && mouseLocation.X < client.X + client.Width + LeftRightBorder) { int newDragValue = max; if (newDragValue != dragValue) { int old = dragValue; dragValue = newDragValue; Invalidate(old, newDragValue); } } } else { if (dragValue != value) { int old = dragValue; dragValue = value; Invalidate(old, value); } } } } } }