Microsoft KB Archive/317479

From BetaArchive Wiki
Knowledge Base


HOW TO: Draw a Rubber Band or Focus Rectangle in Visual Basic .NET

Article ID: 317479

Article Last Modified on 4/21/2006



APPLIES TO

  • Microsoft .NET Framework Class Libraries 1.0
  • Microsoft .NET Framework Class Libraries 1.1
  • Microsoft Visual Basic .NET 2002 Standard Edition
  • Microsoft Visual Basic .NET 2003 Standard Edition
  • Microsoft Windows XP Professional
  • Microsoft Windows XP Professional for Itanium-based systems



This article was previously published under Q317479

For a Microsoft Visual Studio .NET C# version of this article, see 314945.

IN THIS TASK

SUMMARY

A rubber band or focus rectangle is a rectangle that tracks with the mouse pointer while you hold down the left mouse button. This technique is commonly used to delimit a selection in response to user mouse-pointer input. In the graphics device interface (GDI), these rectangles are commonly implemented by using raster operations (ROPs). However, the System.Drawing method is based on GDI+ (the successor to GDI), which has no support for ROPs. This article explains another approach for implementing focus rectangles in the .NET Framework.

In the GDI, focus rectangles are commonly drawn by using ROP codes. In particular, the ROP2 codes R2_XORPEN and R2_NOT are frequently used. When you use either of these ROP2 codes, you can erase a previous line by drawing the line again in the same position. This is sometimes known as an exclusive-OR (XOR) effect.

back to the top

Sample Code

Because ROPs are not available in GDI+ and System.Drawing, you must use another approach to draw reversible lines with these tools. For example, you can use Platform Invocation Services (PInvoke) to interoperate with the GDI. However, a solution that uses only managed code is available through the use of the static member ControlPaint::DrawReversibleFrame(). The following code, written in Visual Basic .NET, and ready to be pasted into the form class in a default Visual Basic .NET application, demonstrates this approach:

Public Class Form1
    Inherits System.Windows.Forms.Form

    Dim bHaveMouse As Boolean
    Dim ptOriginal As Point
    Dim ptLast As Point

+[Windows Form Designer generated code]

    ' Convert and Normalize the points and draw the reversible frame.
    Private Sub MyDrawReversibleRectangle(ByVal p1 As Point, ByVal p2 As Point)
        Dim rc As Rectangle
        ' Convert the points to screen coordinates.
        p1 = PointToScreen(p1)
        p2 = PointToScreen(p2)
        ' Normalize the rectangle.
        If (p1.X < p2.X) Then
            rc.X = p1.X
            rc.Width = p2.X - p1.X
        Else
            rc.X = p2.X
            rc.Width = p1.X - p2.X
        End If
        If (p1.Y < p2.Y) Then
            rc.Y = p1.Y
            rc.Height = p2.Y - p1.Y
        Else
            rc.Y = p2.Y
            rc.Height = p1.Y - p2.Y
        End If
        ' Draw the reversible frame.
        ControlPaint.DrawReversibleFrame(rc, Color.Red, FrameStyle.Dashed)
    End Sub

    ' Called when the left mouse button is pressed down.
    Public Sub MyMouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseDown
        ' Make a note that we "have the mouse".
        bHaveMouse = True
        ' Store the "starting point" for this rubber-band rectangle.
        ptOriginal.X = e.X
        ptOriginal.Y = e.Y
        ' Special value lets us know that no previous
        ' rectangle needs to be erased.
        ptLast.X = -1
        ptLast.Y = -1
    End Sub

    ' called when the left mouse button is released
    Public Sub MyMouseUp(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseUp
        ' Set internal flag to know we no longer "have the mouse".
        bHaveMouse = False
        ' If we have drawn previously, draw again in that spot
        ' to remove the lines.
        If (ptLast.X <> -1) Then
            Dim ptCurrent As Point
            ptCurrent.X = e.X
            ptCurrent.Y = e.Y
            MyDrawReversibleRectangle(ptOriginal, ptLast)
        End If
        ' Set flags to know that there is no "previous" line to reverse.
        ptLast.X = -1
        ptLast.Y = -1
        ptOriginal.X = -1
        ptOriginal.Y = -1
    End Sub

    ' Called when the mouse is moved.
    Public Sub MyMouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseMove
        Dim ptCurrent As Point
        ptCurrent.X = e.X
        ptCurrent.Y = e.Y
        ' If we "have the mouse", then we draw our lines.
        If (bHaveMouse) Then
            ' If we have drawn previously, draw again in
            ' that spot to remove the lines.
            If (ptLast.X <> -1) Then
                MyDrawReversibleRectangle(ptOriginal, ptLast)
            End If
            ' Update last point.
            ptLast = ptCurrent
            ' Draw new lines.
            MyDrawReversibleRectangle(ptOriginal, ptCurrent)
        End If
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        bHaveMouse = False
    End Sub
End Class
                

Note that this solution is available only for output on the screen. To draw reversible lines on a graphics object, you must either interoperate with GDI or call Bitmap::LockBits() and manipulate the image bits directly.

back to the top


Additional query words: rubberband rubber-band rect DrawFocusRect XOR NOT invert pen SetROP2 focus rectangle VB

Keywords: kbhowtomaster kbgdiplus kbdswgdi2003swept KB317479