Click here to Skip to main content
15,867,453 members
Articles / Multimedia / GDI+
Article

Sliding Scale Gauge

Rate me:
Please Sign up or sign in to vote.
4.97/5 (40 votes)
17 Oct 2008CPOL4 min read 92.7K   7.9K   98   22
An endless moving graphical scale gauge with a linear representation of data.

Introduction

The sliding scale is a very simple, but fast, performing, and powerful .NET user control, figured as a graphical scale gauge with a linear representation of data. The instrument consists of a static pointer (needle) and a movable linear scale. The static needle refers to the current position of the moving scale, and shows the input values through a graphical position along the scale. The sliding scale is endless, and can represent an unlimited value (type double) at a certain moment.

Background

On the CodeProject, there are several very useful and good-looking instruments already available. I want to take the trouble to add one more to the chain.

This project is developed in C#, with SharpDevelop and .NET 2.0, using GDI+.

The sliding scale is inherited from System.Windows.Forms.UserControl, with an overridden OnPaint method and some new properties:

ValueThe current position of the scale.
ScaleRangeThe visible range of the scale.
LargeTicksCountThe number of large ticks.
SmallTickCountThe number of small ticks.
ShadowEnabledIs the shadow enabled?
ShadowColorThe shadow color of the component.
NeedleColorThe color of the scale needle.

In the code, the following properties from the parent control are used:

BackColorThe background color of the component.
BorderStyleIndicates whether the control should have a border.
ForeColorThe foreground color used to display the text and ticks.

The sliding scale is composed of four layers.

  1. Background (with a background color or transparent) and border.
  2. Linear scale (with a number of small and / or large ticks with their values).
  3. Shadow (for 3D-like look that can be disabled).
  4. Needle.

The complete logic is placed in the OnPaint method. There is a small invariant part for purists, closed in a signed region, which can be moved outside the OnPaint. Everything else happens in a few simple steps:

  1. Calculate the position of the first large tick, that can be showed, and its value.
  2. Iterate over all other large ticks, and draw them and their value numbers.
  3. Iterate over all small ticks, if exists, and draw them.
  4. Draw the shadow, if enabled, with a LinearGradientBrush.
  5. Draw the needle over all others in its defined color.
C#
protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);
        
    // Draw simple text, don't waste time with luxus render:
    e.Graphics.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;
            
    #region Can be moved outside OnPaint ...
            
    // Calculate help variables
    int W = this.ClientRectangle.Width;
    int H = this.ClientRectangle.Height;

    int Wm = W / 2;
    int Hm = H / 2;
            
    // Calculate distances between ticks
    double largeTicksDistance = scaleRange / largeTicksCount;
    double smallTicksDistance = largeTicksDistance / (smallTicksCount+1);
            
    // Calculate number of pixel between small ticks
    float smallTicksPixels = (float)(W/scaleRange*smallTicksDistance);
            
    #endregion Can be moved outside OnPaint
            
    // Calculate first large tick value and position
    double tickValue = Math.Floor((curValue-scaleRange/2) / 
                       largeTicksDistance) * largeTicksDistance;
    float  tickPosition = (float)Math.Floor(Wm - W/scaleRange*(curValue-tickValue));
            
    // Create drawing resources
    Pen pen = new Pen(ForeColor);
    Brush brush = new SolidBrush(ForeColor);
            
    // For all large ticks
    for (int L=0; L<=largeTicksCount; L++)
    {
        // Draw large tick
        e.Graphics.DrawLine(pen, tickPosition-0,0, tickPosition-0,15);
        e.Graphics.DrawLine(pen, tickPosition-1,0, tickPosition-1,15);

        // Draw large tick numerical value
        StringFormat sf = new StringFormat();
        sf.Alignment = StringAlignment.Center;
        e.Graphics.DrawString(Math.Round(tickValue,2).ToString(),
                              Font, brush,
                              new PointF(tickPosition, Hm),sf);
                
        // For all small ticks
        for (int S=1; S<=smallTicksCount; S++)
        {
            // Update tick value and position
            tickValue += smallTicksDistance;
            tickPosition += smallTicksPixels;
                    
            // Draw small tick
            e.Graphics.DrawLine(pen, tickPosition,0,tickPosition,10);
        }
                
        // Update tick value and position
        tickValue += smallTicksDistance;
        tickPosition += smallTicksPixels;
    }
            
    // Dispose drawing resources
    brush.Dispose();
    pen.Dispose();
            
            
    if (ShadowEnabled)
    {
        LinearGradientBrush LGBrush = null;
                
        // Draw left side shadow
        LGBrush = new LinearGradientBrush(new Rectangle(0, 0, Wm, H),
                                          Color.FromArgb(255, ShadowColor),
                                          Color.FromArgb(0, BackColor),
                                                  000, true);
        e.Graphics.FillRectangle(LGBrush, new Rectangle(0,0, Wm, H));
        
        // Draw right side shadow
        LGBrush = new LinearGradientBrush(new Rectangle(Wm+1, 0, Wm, H),
                                          Color.FromArgb(255, ShadowColor),
                                          Color.FromArgb(0, BackColor),
                                          180, true);
        e.Graphics.FillRectangle(LGBrush, new Rectangle(Wm+1, 0, Wm, H));
          
        LGBrush.Dispose();
    }

    // Draw scale needle
    e.Graphics.DrawLine(new Pen(NeedleColor), Wm-0,0, Wm-0,H);
    e.Graphics.DrawLine(new Pen(NeedleColor), Wm-1,0, Wm-1,H);
}

Using the code

This control has a good set of default property values so that, once included in your own solution, it can be simply selected from the tools palette, dropped to your form, and used immediately. Otherwise, there are only a few other listed properties to be configured. You just need one line of code to get it working:

C#
slidingScale1.Value = your value here!

The included archive files contain the complete source code and the compiled binaries of the component, and a simple test application.

Possible enhancements

There are many possibilities to improve this control. Here are some ideas, if someone wants to do it:

Owing to the LinearGradientBrush shading, there is a three dimensional feel, the sliding scale looks already like a real instrument. I personally miss some flexibility in order to draw the numbers on the face of the scale and to customize the lengths of the ticks.

In order to set up the instrument so that it behaves as a real instrument, we must look at two important areas:

  1. The scale should be limited and/or round.
    • A real scale is not an endless ribbon, but it has a real size.
    • Limiting the scale is not a hard problem. We can do that by adding two new properties, MinValue and MaxValue, and by controlling the changes of the existing Value property. Only values from a defined range should be accepted.
    • A round scale is not that simple to realize. For this feature, we need several new properties and a good dose of calculations.
  2. The scale shouldn't react promptly to value changing.
    • A real scale has a self moment of inertia, and cannot jump in a short time from one end to the other. Value changing must be realized so that the scale moves itself and slides smoothly in small steps from the old position to the new one. It should immediately begin sliding/rotating from the current position towards and arrive at the end position after a certain time.
    • This behavior can be realized so that we first set a new value as the desired value when the current value should be changed, and enable a timer which increments (decrements) the current value in small steps until it will arrive at the desired one.
    • Simpler said, we should make an animated sliding scale.

These are some other desired features:

  • Vertical scale representation.
  • Scale with marked tolerance limits (OTL, UTL, ...).
  • Scale with different colored regions.

The sliding scale shown here, in terms of measurement technology, is an “indicator”. We can make it a “control”. Therefore, we should override the OnMouseDown and OnMouseMove methods to process mouse events, and implement a ChangeValue method to announce value changing.

Conclusion

This is the preliminary version of the control, and many features have to be implemented yet. I will attempt to cover this as soon as possible.

Any suggestions/comments/feedback is welcome and highly appreciated.

If you like it, please vote, and if you use it commercially, describe your success story in the discussion board below.

History

  • 08.10.2008 - Version 1.0 released.
  • 16.10.2008 - Version 2.0 released. Added new properties and vertical orientation.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Systems Engineer
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionWPF Version Pin
mobtadi18-May-22 3:54
mobtadi18-May-22 3:54 
QuestionGood Job Pin
mobtadi18-May-22 2:20
mobtadi18-May-22 2:20 
Questionhow to add into toolbox? Pin
Hüseyin Koç13-Nov-19 3:07
Hüseyin Koç13-Nov-19 3:07 
QuestionInverted Values Along Scale Pin
Vladimir J Arias L11-Aug-17 5:25
Vladimir J Arias L11-Aug-17 5:25 
QuestionVertical Control Pin
Vladimir J Arias L7-Jul-15 10:43
Vladimir J Arias L7-Jul-15 10:43 
AnswerRe: Vertical Control Pin
Tefik Becirovic28-Jul-15 8:36
Tefik Becirovic28-Jul-15 8:36 
QuestionGreatWork,But is there a version for MFC? Pin
Jason.LYJ5-Sep-13 15:45
professionalJason.LYJ5-Sep-13 15:45 
GeneralVery impressive Pin
N. Henrik Lauridsen12-Jul-13 0:24
N. Henrik Lauridsen12-Jul-13 0:24 
GeneralMy vote of 5 Pin
Mazen el Senih8-Jun-12 5:06
professionalMazen el Senih8-Jun-12 5:06 
GeneralRe: My vote of 5 Pin
Tefik Becirovic10-Jun-12 23:20
Tefik Becirovic10-Jun-12 23:20 
NewsRe: My vote of 5 Pin
Mazen el Senih11-Jun-12 4:39
professionalMazen el Senih11-Jun-12 4:39 
Questioncan this be used in a web app? Pin
moh1234_uk21-Feb-12 3:49
moh1234_uk21-Feb-12 3:49 
AnswerRe: can this be used in a web app? Pin
Tefik Becirovic22-Feb-12 4:12
Tefik Becirovic22-Feb-12 4:12 
GeneralRe: can this be used in a web app? Pin
Tefik Becirovic22-Feb-12 4:20
Tefik Becirovic22-Feb-12 4:20 
Here is one SlidingScaleWebTest.aspx test page:
<br />
<%@ Page Language="C#" AutoEventWireup="true" %><br />
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" <br />
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><br />
<html xmlns="http://www.w3.org/1999/xhtml"><br />
<head runat="server"><br />
    <title>SlidingScale Web Test</title><br />
    <script type="text/javascript"><br />
        function ChangeSlidingScale(value) {<br />
            slidingScale = document.getElementById("SlidingScale");<br />
            slidingScale.Value += value;<br />
            label.innerHTML = slidingScale.Value<br />
        }<br />
    </script><br />
</head><br />
<body><br />
    <center><br />
        <form id="form1" runat="server"><br />
        <div><br />
            <br /><br />
            <object id="SlidingScale" classid="http:SlidingScale.dll#Instruments.SlidingScale"<br />
                height="45" width="254" viewastext><br />
                <param name="Value" value="100" /><br />
            </object><br />
            <br /><br />
            <br /><br />
            <input type="button" onclick="ChangeSlidingScale(-10)" value=" << " /><br />
            <input type="button" onclick="ChangeSlidingScale(-1)" value=" < " /><br />
            <input type="button" onclick="ChangeSlidingScale(+1)" value=" > " /><br />
            <input type="button" onclick="ChangeSlidingScale(+10)" value=" >> " /><br />
            <br /><br />
            <br /><br />
            <div id="label">100</div><br />
        </div><br />
        </form><br />
    </center><br />
</body><br />
</html><br />


[ TEST IMAGE HERE ]

Tefik Becirovic

modified 22-Feb-12 11:11am.

GeneralMy vote of 5 Pin
Manoj Kumar Choubey17-Feb-12 2:07
professionalManoj Kumar Choubey17-Feb-12 2:07 
GeneralWonderful control Pin
BeauGauge00122-Mar-11 4:05
BeauGauge00122-Mar-11 4:05 
Generallooks nice, but I'd add... Pin
Seishin#17-Oct-08 22:17
Seishin#17-Oct-08 22:17 
GeneralVery Nice Pin
Paul Conrad17-Oct-08 8:58
professionalPaul Conrad17-Oct-08 8:58 
GeneralNice Pin
Ennis Ray Lynch, Jr.17-Oct-08 8:35
Ennis Ray Lynch, Jr.17-Oct-08 8:35 
GeneralNice little piece... Pin
Paw Jershauge9-Oct-08 3:02
Paw Jershauge9-Oct-08 3:02 
AnswerRe: Nice little piece... Pin
Tefik Becirovic9-Oct-08 3:19
Tefik Becirovic9-Oct-08 3:19 
GeneralRe: Nice little piece... Pin
Ciorbea10-Jun-13 8:13
Ciorbea10-Jun-13 8:13 

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.