Click here to Skip to main content
15,885,782 members
Articles / Desktop Programming / Windows Forms
Article

TimeSlider - A time-based TrackBar

Rate me:
Please Sign up or sign in to vote.
4.35/5 (11 votes)
6 Apr 20063 min read 104.5K   3.6K   71   16
A custom trackbar control using dates instead of integer values.

Sample Image

Introduction

A new work project involved a video playback system, with the ability to annotate key frames and segments within the video as points of interest. Other parties could then come back and search for annotated frames within the video, thus being able to jump directly to key images rather than having to look through the entire file.

It stuck me early on that it would be nice to have a trackbar available below the video, similar to the Windows Media Player or the QuickTime viewer. Even better would be one that kept track of where within the video the user is, and could show key information about video start and end times. I am a long-time CodeProject fan, and this quickly struck me as a chance to give something back for all the code I've stolen over the years. Thus was born the idea of the TimeSlider control.

Using the control

The TimeSlider control can be used like any other .NET control - just add it to your toolbox and then drag it onto a form. All properties are exposed through the standard property grid within VS.NET.

The TimeSlider control is basically a trackbar control that uses DateTime values instead of integer values as input (and output). It is based on the standard Windows trackbar, but properties such as Minimum, Maximum, and Value are now DateTime values, while the SmallChange, LargeChange, and TickFrequency properties are now TimeSpan values.

In addition, the TimeSlider provides some new functionality that either made sense to me or was specifically needed for my project. These are:

  • Turn on or off labels that show the minimum, maximum, and the current value. The format for labels is defined through the Format and CustomFormat properties. I also extended the number of available "standard" formats to include things like ShortDateLongTime and NoDateShortTime.
  • View current values as either absolute DateTime values or as duration into the time period.
  • Ability to auto-increment the maximum date value if the incoming date value is greater than the defined maximum. This is useful for live video feeds, where you don't know what the end date is.
  • Ability to define a segment of interest within a timeline, which shows up as a segment bar on the control.

Using the code

The majority of the code behind the TimeSlider control is pretty straightforward and not worth special note here. The control uses the Windows TrackBar as its base class. Under the hood, the TrackBar is always fed values between 0 and 100, which are translated from date values before being passed on to the control. In reverse fashion, integer values fed from the control when the puck is moved are translated into date values and then passed on to the container.

C#
double nTicksMin = mdtMin.Ticks;
double nTicksMax = mdtMax.Ticks;

double d1 = ( (double)base.Value ) / 100.0;
double nTicksCur = d1 * ( nTicksMax - nTicksMin ) + nTicksMin;
mdtCur = new DateTime((long)nTicksCur);
DrawLabels();

The one point of interest is the ability to draw onto the existing TrackBar control. The Windows controls are set up to either perform all the drawing, in which case no OnPaint events are sent to a sub-classed control, or to do none of the drawing, expecting the new control to perform all painting operations during the OnPaint event.

In my case, I wanted the TrackBar to draw itself, but allow me to draw a segment bar on top. To get this working, I had to perform some trickery, swapping the UserPaint flag just long enough to convince the base control to draw itself.

C#
public TimeSlider() {

    ...

    // this call says "I'll draw it myself"
    this.SetStyle(ControlStyles.AllPaintingInWmPaint |
        ControlStyles.ResizeRedraw |
        ControlStyles.UserPaint, true);

    ...
}

protected override void OnPaint(PaintEventArgs e) {
    base.SetStyle(ControlStyles.UserPaint, false);
    base.Refresh();

    if ( mbShowSegment ) {
        mGraphics.FillRectangle(mSegmentBrush,
        new Rectangle(mSegmentRect.X,
        mSegmentRect.Y,
        mSegmentRect.Width,
        mSegmentRect.Height));
    }

    base.SetStyle(ControlStyles.UserPaint, true);
}

Caveats

The control only behaves properly in horizontal layout mode, and looks best with the tick style set to BottomRight. This would definitely be a candidate for version 2 (if enough interest exists).

History

This is version 1 of this control. Please feel free to report errors, issues, or requests.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionMultiple Track Points Pin
Su Win17-Aug-08 23:29
Su Win17-Aug-08 23:29 
Answerimproved granularity of base value .... Pin
jsytniak3-Jun-08 8:55
jsytniak3-Jun-08 8:55 
NewsSuspendLayout - never really resumes [modified] Pin
jsytniak23-Mar-08 7:42
jsytniak23-Mar-08 7:42 
GeneralTimeSlider set value on load Pin
trampax6622-Nov-07 1:37
trampax6622-Nov-07 1:37 
GeneralMulitple TrackPoints Pin
bizzysim6-Jul-07 9:42
bizzysim6-Jul-07 9:42 
QuestionRe: Mulitple TrackPoints Pin
Ibrahim Dwaikat30-Oct-07 9:11
Ibrahim Dwaikat30-Oct-07 9:11 
GeneralSome suggested updates Pin
wildman_32320-Apr-07 5:15
wildman_32320-Apr-07 5:15 
Thanks for the great control!!! It was just what I needed.

I was playing with the control and noticed that the Segment bar did not match up with the Tick marks...
Example: if one set the SegmentStart to the Minimum the segments bar x location would be 0... not the location of the first tick...
at any rate here are my suggested updates

The values I used are arbitrary. They seem to work on my computer with my monitor… I see no reason why they would not work elsewhere… but just in case I put them in a place (just like the rest) that is easy to find and change.

3 new consts at the top:
<br />
private const int SEGMENT_OFFSET = 13;<br />
private const int SEGMENT_OFFSETMAX = 3;<br />
private const int SEGMENT_MAXWIDTH = 26;<br />

Also in OnPaint...
If one does not add the mGraphics = Graphics.FromHwnd(base.Handle); mentioned by kada123 the control will not draw totally.

in DrawLabels:
<br />
if ( mbShowSegment ) {<br />
    double nTicksMin = mdtMin.Ticks;<br />
    double nTicksMax = mdtMax.Ticks;<br />
    double nTicksSegMin = mdtSegmentStart.Ticks;<br />
    double nTicksSegMax = mdtSegmentEnd.Ticks;<br />
<br />
    double dMinPercent = ( nTicksSegMin - nTicksMin ) / ( nTicksMax - nTicksMin );<br />
    double dMaxPercent = ( nTicksSegMax - nTicksMin ) / ( nTicksMax - nTicksMin );<br />
    double dMinX = (double)Width * dMinPercent;<br />
    double dMaxX = (double)Width * dMaxPercent;<br />
    mSegmentRect.X = (int)dMinX + SEGMENT_OFFSET;<br />
    mSegmentRect.Y = SEGMENT_YPOS;<br />
    mSegmentRect.Width = (int)(dMaxX - dMinX) - SEGMENT_OFFSETMAX;<br />
    if (mSegmentRect.Width >= this.Width - SEGMENT_MAXWIDTH)<br />
        mSegmentRect.Width = this.Width - SEGMENT_MAXWIDTH;<br />
	mSegmentRect.Height = SEGMENT_HEIGHT;<br />
}<br />


WILDMAN


-- modified at 11:24 Friday 20th April, 2007
GeneralFlickering Pin
q23r23-Nov-06 19:33
q23r23-Nov-06 19:33 
GeneralRe: Flickering Pin
annae9021-May-13 2:17
annae9021-May-13 2:17 
QuestionSegment Display doen't work [modified] Pin
kada1237-Oct-06 22:11
kada1237-Oct-06 22:11 
AnswerRe: Segment Display doen't work Pin
kada1239-Oct-06 6:02
kada1239-Oct-06 6:02 
AnswerRe: Segment Display doesn't work [modified] Pin
jsytniak21-Mar-08 14:46
jsytniak21-Mar-08 14:46 
QuestionDrawing labels twice for each update? Pin
MetaGeek1-Aug-06 7:27
MetaGeek1-Aug-06 7:27 
GeneralThanks + few points. Pin
Amit_8-May-06 7:16
Amit_8-May-06 7:16 
GeneralLink fix please Pin
fwsouthern6-Apr-06 16:23
fwsouthern6-Apr-06 16:23 
GeneralRe: Link fix please Pin
Tom Holt6-Apr-06 18:46
Tom Holt6-Apr-06 18:46 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.