Recipe 9.26. Creating a Rubber-Band Rectangular Selection


Problem

You want to add " rubber-band selection" to your graphics, giving the user the ability to click and drag with the mouse to select a rectangular region of an image.

Solution

Sample code folder: Chapter 09\RubberBand

Use the RubberBand class presented here to use one of three different-appearing rubber-band selection algorithms.

Discussion

You've probably seen rubber-band selection in action when cropping images or working with screen-grabbing programs, paint programs, and so on. The RubberBand class presented here can be included in any project in which you want to let the user select a rectangular area of an image in this way.

The complete code for the class is presented below. The RubberBandStyle enumeration and the public Style property work together to let you set the RubberBand object's appearance while in operation. While the user drags the mouse, the selected area is outlined with either a dashed-line rectangle (as in Figure 9-37, below), a solid line with inverted colors, or a solid-filled box with inverted colors.

There are two overloaded constructors in this class, which let you instantiate a RubberBand object in three different ways. (The plan was to have only one constructor with two optional arguments, but Visual Basic does not permit structure objectsColor, in this caseto be optional.) You can set the RubberBand's Style and BackColor properties when you create the object, or you can set these properties later. You do need to indicate the control on which the RubberBand is to operate, so the painting on the screen can coordinate with the surface of the control. The Start(), Stretch(), and Finish() methods are called from the program that creates the RubberBand object to update the rectangular selection. Once "rubberbanding" is complete, the Rectangle property returns the results. These methods are demonstrated in the calling code presented later.

Here's the code for the RubberBand class:

 Public Class RubberBand    ' ----- The three types of rubber bands.    Public Enum RubberBandStyle       DashedLine       ThickLine       SolidBox    End Enum    ' ----- The current drawing state.    Public Enum RubberBandState       Inactive       FirstTime       Active    End Enum    ' ----- Class-level variables.    Private BasePoint As Point    Private ExtentPoint As Point    Private CurrentState As RubberBandState    Private BaseControl As Control    Public Style As RubberBandStyle    Public BackColor As Color    Public Sub New(ByVal useControl As Control, _          Optional ByVal useStyle As RubberBandStyle = _          RubberBandStyle.DashedLine)       ' ----- Constructor with one or two parameters.       BaseControl = useControl       Style = useStyle       BackColor = Color.Black    End Sub    Public Sub New(ByVal useControl As Control, _          ByVal useStyle As RubberBandStyle, _          ByVal useColor As Color)       ' ----- Constructor with three parameters.       BaseControl = useControl       Style = useStyle       BackColor = useColor    End Sub    Public ReadOnly Property Rectangle() As Rectangle       Get          ' ----- Return the bounds of the   rubber-band area.          Dim result As Rectangle          ' ----- Ensure the coordinates go left to          ' right, top to bottom.          result.X = IIf(BasePoint.X < ExtentPoint.X, _             BasePoint.X, ExtentPoint.X)          result.Y = IIf(BasePoint.Y < ExtentPoint.Y, _             BasePoint.Y, ExtentPoint.Y)          result.Width = Math.Abs(ExtentPoint.X - BasePoint.X)          result.Height = Math.Abs(ExtentPoint.Y - BasePoint.Y)          Return result       End Get    End Property    Public Sub Start(ByVal x As Integer, ByVal y As Integer)       ' ----- Start drawing the rubber band. The user must       '       call Stretch() to actually draw the first       '       band image.       BasePoint.X = x       BasePoint.Y = y       ExtentPoint.X = x       ExtentPoint.Y = y       Normalize(BasePoint)       CurrentState = RubberBandState.FirstTime    End Sub    Public Sub Stretch(ByVal x As Integer, ByVal y As Integer)       ' ----- Change the size of the rubber band.       Dim newPoint As Point       ' ----- Prepare the new stretch point.       newPoint.X = x       newPoint.Y = y       Normalize(newPoint)       Select Case CurrentState          Case RubberBandState.Inactive             ' ----- Rubber band not in use.             Return          Case RubberBandState.FirstTime             ' ----- Draw the initial rubber band.             ExtentPoint = newPoint             DrawTheRectangle()             CurrentState = RubberBandState.Active          Case RubberBandState.Active             ' ----- Undraw the previous band, then             '       draw the new one.             DrawTheRectangle()             ExtentPoint = newPoint             DrawTheRectangle()       End Select    End Sub    Public Sub Finish()       ' ----- Stop drawing the rubber band.       DrawTheRectangle()       CurrentState = 0    End Sub    Private Sub Normalize(ByRef whichPoint As Point)       ' ----- Don't let the rubber band go outside the view.       If (whichPoint.X < 0) Then whichPoint.X = 0       If (whichPoint.X >= BaseControl.ClientSize.Width) _          Then whichPoint.X = BaseControl.ClientSize.Width - 1       If (whichPoint.Y < 0) Then whichPoint.Y = 0       If (whichPoint.Y >= BaseControl.ClientSize.Height) _          Then whichPoint.Y = BaseControl.ClientSize.Height - 1    End Sub    Private Sub DrawTheRectangle()       ' ----- Draw the rectangle on the control or       '       form surface.       Dim drawArea As Rectangle       Dim screenStart, screenEnd As Point       ' ----- Get the square that is the   rubber-band area.       screenStart = BaseControl.PointToScreen(BasePoint)       screenEnd = BaseControl.PointToScreen(ExtentPoint)       drawArea.X = screenStart.X       drawArea.Y = screenStart.Y       drawArea.Width = (screenEnd.X - screenStart.X)       drawArea.Height = (screenEnd.Y - screenStart.Y)       ' ----- Draw using the user-selected style.       Select Case Style          Case RubberBandStyle.DashedLine             ControlPaint.DrawReversibleFrame( _                drawArea, Color.Black, FrameStyle.Dashed)          Case RubberBandStyle.ThickLine             ControlPaint.DrawReversibleFrame( _                drawArea, Color.Black, FrameStyle.Thick)          Case RubberBandStyle.SolidBox             ControlPaint.FillReversibleRectangle( _                drawArea, BackColor)       End Select    End Sub End Class 

To demonstrate the RubberBand class, the following code creates an instance and calls its Start(), Stretch(), and Finish() methods based on the user's mouse activities. When the mouse button is first depressed, the code calls the Start() method. As the mouse is moved, the Stretch() method is called to continuously update the visible selection rectangle. When the mouse button is released, the Finish() method completes the selection process. At this point, the read-only Rectangle property returns a complete description of the selected area:

 Public Class Form1    ' ----- Adust the second and third arguments to    ' see different methods.    Dim SelectionArea As RubberBand = New RubberBand(Me, _       RubberBand.RubberBandStyle.DashedLine, Color.Gray)    Private Sub Form1_MouseDown(ByVal sender As Object, _          ByVal e As System.Windows.Forms.MouseEventArgs) _          Handles MyBase.MouseDown       ' ----- Start   rubber-band tracking.       SelectionArea.Start(e.X, e.Y)    End Sub    Private Sub Form1_MouseMove(ByVal sender As Object, _          ByVal e As System.Windows.Forms.MouseEventArgs) _          Handles MyBase.MouseMove       ' ----- Update the rubber-band display area.       SelectionArea.Stretch(e.X, e.Y)    End Sub    Private Sub Form1_MouseUp(ByVal sender As Object, _          ByVal e As System.Windows.Forms.MouseEventArgs) _          Handles MyBase.MouseUp       ' ----- Finished with the selection.       SelectionArea.Finish()       Me.Refresh()    End Sub    Private Sub Form1_Paint(ByVal sender As Object, _          ByVal e As System.Windows.Forms.PaintEventArgs) _          Handles MyBase.Paint       ' ----- Add some interest to the form surface.       Dim canvas As Graphics = e.Graphics       Dim polygonPoints() As Point = {New Point(300, 150), _          New Point(200, 300), New Point(400, 300)}       ' ----- Draw some shapes and text.       canvas.FillEllipse(New SolidBrush(Color.Red), _          10, 20, 200, 150)       canvas.FillRectangle(New SolidBrush(Color.Blue), _          100, 100, 250, 100)       canvas.FillPolygon(New SolidBrush(Color.Green), _          polygonPoints)       canvas.DrawString(  SelectionArea.Rectangle.ToString, _          New Font("Arial", 12), Brushes.Black, 0, 0)    End Sub End Class 

Figure 9-37 shows the results of running this demonstration code to select a rectangular area on the form. In this case the mouse was dragged down and to the right to select the area, but the code compensates for dragging in any direction and returns a proper rectangle.

Figure 9-37. The RubberBand class lets you select rectangular areas of any graphics area





Visual Basic 2005 Cookbook(c) Solutions for VB 2005 Programmers
Visual Basic 2005 Cookbook: Solutions for VB 2005 Programmers (Cookbooks (OReilly))
ISBN: 0596101775
EAN: 2147483647
Year: 2006
Pages: 400

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net