Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

TimeSlider - A time-based TrackBar

0.00/5 (No votes)
6 Apr 2006 1  
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.

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.

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