Click here to Skip to main content
Click here to Skip to main content

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

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:

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

Share

About the Author

chimeric69
Web Developer
Australia Australia
No Biography provided

Comments and Discussions

 
GeneralMy vote of 5 Pinmembermanoj kumar choubey26-Feb-12 21:51 
Generalfloorplan PinmemberAshar Shah9-Nov-09 4:00 
GeneralArgumentOutOfRangeException PinmemberDarchangel11-Aug-09 4:50 
GeneralLines Label Pinmembercds toecutter4-Jun-09 15:57 
GeneralC# Rubberband Lines Pinmembercarlmalden3-Nov-08 7:35 
GeneralRe: C# Rubberband Lines Pinmembercarlmalden3-Nov-08 8:07 
QuestionEquation Pinmembercutenush20-Nov-07 20:01 
QuestionHow does it do that? PinmemberRobinLetMeLogin19-Jan-07 2:21 
AnswerRe: How does it do that? PinmemberIlíon15-Jun-08 7:20 
GeneralRe: How does it do that? Pinmemberchimeric6915-Jun-08 20:48 
GeneralRe: How does it do that? PinmemberIlíon15-Jun-08 23:52 
GeneralRe: How does it do that? Pinmembermiliu30-May-09 16:40 
Generalgetting started Pinmembercgriff1-Feb-06 20:01 
GeneralRe: getting started Pinmemberchimeric691-Feb-06 23:10 
AnswerRe: getting started PinmemberMichael Thornberry2-May-06 6:25 
GeneralRe: getting started Pinmemberchimeric692-May-06 22:41 
Generalfiles missing from .zip file Pinmemberdfellman2-Nov-05 6:42 
AnswerRe: files missing from .zip file Pinmemberchimeric692-Nov-05 18:12 

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

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

| Advertise | Privacy | Mobile
Web02 | 2.8.140821.2 | Last Updated 2 Nov 2005
Article Copyright 2005 by chimeric69
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid