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

Rubberband Lines

Rate me:
Please Sign up or sign in to vote.
4.74/5 (17 votes)
2 Nov 20053 min read 95K   1.3K   41   24
Using the rubberband line as a ruler.

Sample Image - Rubberbands.jpg

Introduction

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.

Background

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:

VB
' 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:

VB
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.

VB
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.

VB
Public Class Form1
    Private WithEvents _ruler As MouseRuler

    Public Sub New()

        ' This call is required by the Windows Form Designer.
        InitializeComponent()

        ' 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

History

Changes made to date:

  • None.

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
Software Developer (Senior)
Australia Australia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Questionexcellent! Pin
Southmountain25-May-22 15:30
Southmountain25-May-22 15:30 
QuestionPicturebox control Pin
Member 1327605623-Jun-17 9:53
Member 1327605623-Jun-17 9:53 
GeneralMy vote of 5 Pin
Manoj Kumar Choubey26-Feb-12 21:51
professionalManoj Kumar Choubey26-Feb-12 21:51 
Generalfloorplan Pin
Ashar Shah9-Nov-09 4:00
Ashar Shah9-Nov-09 4:00 
GeneralArgumentOutOfRangeException Pin
Darchangel11-Aug-09 4:50
Darchangel11-Aug-09 4:50 
GeneralLines Label Pin
cds toecutter4-Jun-09 15:57
cds toecutter4-Jun-09 15:57 
GeneralC# Rubberband Lines Pin
carlmalden3-Nov-08 7:35
carlmalden3-Nov-08 7:35 
GeneralRe: C# Rubberband Lines Pin
carlmalden3-Nov-08 8:07
carlmalden3-Nov-08 8:07 
GeneralRe: C# Rubberband Lines Pin
Southmountain30-May-22 7:17
Southmountain30-May-22 7:17 
GeneralThank you!!! Pin
BobLeavell6-Aug-08 16:40
BobLeavell6-Aug-08 16:40 
QuestionSave the Lines Pin
cds toecutter2-Aug-08 0:58
cds toecutter2-Aug-08 0:58 
AnswerRe: Save the Lines Pin
BobLeavell6-Aug-08 16:43
BobLeavell6-Aug-08 16:43 
QuestionEquation Pin
cutenush20-Nov-07 20:01
cutenush20-Nov-07 20:01 
QuestionHow does it do that? Pin
RobinLetMeLogin19-Jan-07 2:21
RobinLetMeLogin19-Jan-07 2:21 
Hi, nice code, thanks for sharing this.

I am a beginner to .Net drawing and so unfortunately cant quite see how this is working. I am referring to the way that the line/text gets drawn over whatever is on the background graphics object, yet it 'dissapears' and gets redrawn as you mouse drag it around. Basically what I dont understand here is how come once a line has been drawn it is no longer part of that graphics object. I understand that the line is redrawn, but I dont see anything in the code that 'removes' the line from its old location. The graphics that made up the background is not getting redrawn...so I dont get how that works.

Does my question make sense? Please try explain this to me, its killing me!! Smile | :)
AnswerRe: How does it do that? Pin
Ilíon15-Jun-08 7:20
Ilíon15-Jun-08 7:20 
GeneralRe: How does it do that? Pin
AllanNielsen15-Jun-08 20:48
AllanNielsen15-Jun-08 20:48 
GeneralRe: How does it do that? Pin
Ilíon15-Jun-08 23:52
Ilíon15-Jun-08 23:52 
GeneralRe: How does it do that? Pin
miliu30-May-09 16:40
miliu30-May-09 16:40 
Generalgetting started Pin
cgriff1-Feb-06 20:01
cgriff1-Feb-06 20:01 
GeneralRe: getting started Pin
AllanNielsen1-Feb-06 23:10
AllanNielsen1-Feb-06 23:10 
AnswerRe: getting started Pin
Michael Thornberry2-May-06 6:25
Michael Thornberry2-May-06 6:25 
GeneralRe: getting started Pin
AllanNielsen2-May-06 22:41
AllanNielsen2-May-06 22:41 
Generalfiles missing from .zip file Pin
dfellman2-Nov-05 6:42
dfellman2-Nov-05 6:42 
AnswerRe: files missing from .zip file Pin
AllanNielsen2-Nov-05 18:12
AllanNielsen2-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.