Click here to Skip to main content
13,556,206 members
Click here to Skip to main content
Add your own
alternative version


40 bookmarked
Posted 2 Nov 2005

Rubberband Lines

, 2 Nov 2005
Rate this:
Please Sign up or sign in to vote.
Using the rubberband line as a ruler.

Sample Image - Rubberbands.jpg


This article explains the process I went through to create a small class used to create a "Rubberband" style ruler that can be used in any project. It uses a technique in GDI+ that replaces the ControlPaint.DrawReversibleLine which has many issues which I won't go into here. Please note that this code was written using VS2005 but there is no reason it wouldn't work in earlier versions, just make sure you change the Using commands.


I was trying to create an application that required I draw a floor plan, and this lead to an issue of how to display to the user the length of the wall to be drawn. I initially started with the well known and documented .NET method DrawReversibleLine in the ControlPaint class. But this lead to many issues, some of which were world coordinate correlation, painting issues (XOR drawing is flawed in many ways), color choices (there are none), and others, but they were the main ones. So I decided to write my own class.

Using the code

I started by keeping the reversible line code in MouseDown, MouseMove and MouseUp events, this can be found in many articles about drawing reversible lines, so I won't go into the specifics. In brief though, MouseDown stores the start point, MouseMove does the hard work in setting the current point and invalidating the control surface so that it will repaint, and then finally the MouseUp event fires the event to inform listeners that the two points have been defined.

There are a couple of tricks in this implementation of rubberband lines that step outside of the norm, and they are what I'd like to share.

The first is the addition of a text label in the middle of the line (rotating with the line as it moves) which displays the line's length. The second is the way in which the class only draws the sections of the control that it has changed.

Text Label (rotating text)

This was the hardest thing to get working but a few features in the GDI+ library made the task easier. The first thing to overcome was the length itself, but basic Trigonometry answered that:

' length^2 = width^2 + height^2

length = Math.Sqrt(rect.Width ^ 2 + rect.Height ^ 2)

Now all I had to do was to put that value onto the line rotated to follow the line, and to do that I needed the angle to rotate the text by. Again, Trig came to the rescue, giving me the following answer:

angle = Math.Atan((p1.Y - p2.Y) / (p1.X - p2.X)) * (180 / Math.PI)

Now having both the LineLength and the Angle functions, I put together the following section which I added to the Paint event (if the mouse was still pressed). The matrix is used to perform the rotation around the midpoint of the line, so that when the ellipse and text are drawn, they are actually drawn on a rotated graphics device. The string format is just used to ensure the text is centered on the line, this worked much better than trying to draw the text within the rectangle used to draw the ellipse. The purpose of the ellipse is to ensure that the text can always be easily read regardless of the background.

Using mx As New System.Drawing.Drawing2D.Matrix
    mx.Translate(midPoint.X, midPoint.Y)
    mx.Rotate(Angle(_origin, _last))
    e.Graphics.Transform = mx
    Using sf As New StringFormat()
        Dim ls As String = CInt(LineLength(_origin, _last))
        Dim l As SizeF = e.Graphics.MeasureString(ls, _
                         _parent.Font, _parent.ClientSize, sf)
        sf.LineAlignment = StringAlignment.Center
        sf.Alignment = StringAlignment.Center

        Dim rt As New Rectangle(0, 0, l.Width, l.Height)
        rt.Inflate(3, 3)
        rt.Offset(-(l.Width / 2), -(l.Height / 2))
        Using backBrush As New SolidBrush(_backColor)
            e.Graphics.FillEllipse(backBrush, rt)
        End Using
        Using foreBrush As New SolidBrush(_foreColor)
            e.Graphics.DrawString(ls, _parent.Font, foreBrush, 0, 0, sf)
        End Using
    End Using
End Using

Using the Class

To actually use the class is as easy as adding it to your project, then instantiating the class as needed. The following code uses the class in a form. (In the Dispose method, make sure to dispose off the class.) Note the styles that are set on the form to prevent flickering.

Public Class Form1
    Private WithEvents _ruler As MouseRuler

    Public Sub New()

        ' This call is required by the Windows Form Designer.

        ' Add any initialization after the InitializeComponent() call.
        Me.SetStyle(ControlStyles.OptimizedDoubleBuffer Or _
                    ControlStyles.AllPaintingInWmPaint, True)

        _ruler = New MouseRuler(Form1)
    End Sub

    Private Sub _ruler_CaptureFinished(ByVal sender As Object, _
                ByVal e As CaptureEventArgs) Handles _ruler.CaptureFinished
        'todo:  Add wall between points in CaptureEventArgs
    End Sub
End Class


Changes made to date:

  • None.


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


About the Author

Web Developer
Australia Australia
No Biography provided

You may also be interested in...

Comments and Discussions

QuestionPicturebox control Pin
Member 1327605623-Jun-17 9:53
memberMember 1327605623-Jun-17 9:53 
GeneralMy vote of 5 Pin
manoj kumar choubey26-Feb-12 21:51
membermanoj kumar choubey26-Feb-12 21:51 
Generalfloorplan Pin
Ashar Shah9-Nov-09 4:00
memberAshar Shah9-Nov-09 4:00 
GeneralArgumentOutOfRangeException Pin
Darchangel11-Aug-09 4:50
memberDarchangel11-Aug-09 4:50 
GeneralLines Label Pin
cds toecutter4-Jun-09 15:57
membercds toecutter4-Jun-09 15:57 
GeneralC# Rubberband Lines Pin
carlmalden3-Nov-08 7:35
membercarlmalden3-Nov-08 7:35 
GeneralRe: C# Rubberband Lines Pin
carlmalden3-Nov-08 8:07
membercarlmalden3-Nov-08 8:07 
GeneralThank you!!! Pin
BobLeavell6-Aug-08 16:40
memberBobLeavell6-Aug-08 16:40 
QuestionSave the Lines Pin
cds toecutter2-Aug-08 0:58
membercds toecutter2-Aug-08 0:58 
AnswerRe: Save the Lines Pin
BobLeavell6-Aug-08 16:43
memberBobLeavell6-Aug-08 16:43 
QuestionEquation Pin
cutenush20-Nov-07 20:01
membercutenush20-Nov-07 20:01 
QuestionHow does it do that? Pin
RobinLetMeLogin19-Jan-07 2:21
memberRobinLetMeLogin19-Jan-07 2:21 
AnswerRe: How does it do that? Pin
Ilíon15-Jun-08 7:20
memberIlíon15-Jun-08 7:20 
GeneralRe: How does it do that? Pin
chimeric6915-Jun-08 20:48
memberchimeric6915-Jun-08 20:48 
GeneralRe: How does it do that? Pin
Ilíon15-Jun-08 23:52
memberIlíon15-Jun-08 23:52 
GeneralRe: How does it do that? Pin
miliu30-May-09 16:40
membermiliu30-May-09 16:40 
Generalgetting started Pin
cgriff1-Feb-06 20:01
membercgriff1-Feb-06 20:01 
GeneralRe: getting started Pin
chimeric691-Feb-06 23:10
memberchimeric691-Feb-06 23:10 
AnswerRe: getting started Pin
Michael Thornberry2-May-06 6:25
memberMichael Thornberry2-May-06 6:25 
GeneralRe: getting started Pin
chimeric692-May-06 22:41
memberchimeric692-May-06 22:41 
Generalfiles missing from .zip file Pin
dfellman2-Nov-05 6:42
memberdfellman2-Nov-05 6:42 
AnswerRe: files missing from .zip file Pin
chimeric692-Nov-05 18:12
memberchimeric692-Nov-05 18:12 

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.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web04-2016 | 2.8.180515.1 | Last Updated 2 Nov 2005
Article Copyright 2005 by chimeric69
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid