Microsoft KB Archive/314945

From BetaArchive Wiki
Knowledge Base


How to draw a rubber band rectangle or a focus rectangle in Visual C#

Article ID: 314945

Article Last Modified on 12/11/2006



APPLIES TO

  • Microsoft .NET Framework Class Libraries 1.0
  • Microsoft Visual C# 2005 Express Edition
  • Microsoft Visual C# .NET 2002 Standard Edition
  • Microsoft Windows XP Professional
  • Microsoft Windows XP Professional for Itanium-based systems



This article was previously published under Q314945

For a Microsoft Visual Basic .NET version of this article, see 317479.
This article references the following .NET Framework Class Library namespaces:

  • System.Drawing
  • System.Drawing.Imaging
  • System.Windows.Forms

IN THIS TASK

SUMMARY

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, another approach is required for drawing 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 sample code, written in C# and ready to paste into the form class in a default Microsoft Visual C# application, demonstrates this approach:

Boolean bHaveMouse;
Point   ptOriginal = new Point();
Point   ptLast = new Point();

// Called when the left mouse button is pressed. 
public void MyMouseDown( Object sender, MouseEventArgs e )
{
    // 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;
}
// Convert and normalize the points and draw the reversible frame.
private void MyDrawReversibleRectangle( Point p1, Point p2 )
{
    Rectangle rc = new Rectangle();

    // Convert the points to screen coordinates.
    p1 = PointToScreen( p1 );
    p2 = PointToScreen( p2 );
    // Normalize the rectangle.
    if( p1.X < p2.X )
    {
        rc.X = p1.X;
        rc.Width = p2.X - p1.X;
    }
    else
    {
        rc.X = p2.X;
        rc.Width = p1.X - p2.X;
    }
    if( p1.Y < p2.Y )
    {
        rc.Y = p1.Y;
        rc.Height = p2.Y - p1.Y;
    }
    else
    {
        rc.Y = p2.Y;
        rc.Height = p1.Y - p2.Y;
    }
    // Draw the reversible frame.
    ControlPaint.DrawReversibleFrame( rc, 
                    Color.Red, FrameStyle.Dashed );
}
// Called when the left mouse button is released.
public void MyMouseUp( Object sender, MouseEventArgs e )
{
    // 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 )
    {
        Point ptCurrent = new Point( e.X, e.Y );
        MyDrawReversibleRectangle( ptOriginal, ptLast );
    }
    // Set flags to know that there is no "previous" line to reverse.
    ptLast.X = -1;
    ptLast.Y = -1;
    ptOriginal.X = -1;
    ptOriginal.Y = -1;
}
// Called when the mouse is moved.
public void MyMouseMove( Object sender, MouseEventArgs e )
{
    Point ptCurrent = new Point( e.X, e.Y );
    // If we "have the mouse", then we draw our lines.
    if( bHaveMouse )
    {
        // If we have drawn previously, draw again in
        // that spot to remove the lines.
        if( ptLast.X != -1 )
        {
            MyDrawReversibleRectangle( ptOriginal, ptLast );
        }
        // Update last point.
        ptLast = ptCurrent;
        // Draw new lines.
        MyDrawReversibleRectangle( ptOriginal, ptCurrent );
    }
}
// Set up delegates for mouse events.
protected override void OnLoad(System.EventArgs e)
{
    MouseDown += new MouseEventHandler( MyMouseDown );
    MouseUp += new MouseEventHandler( MyMouseUp );
    MouseMove += new MouseEventHandler( MyMouseMove );
    bHaveMouse = false;
}
                

Note The code should be changed in Visual Studio 2005. When you create a Windows Forms project, Visual C# adds one form to the project by default. This form is named Form1. The two files that represent the form are named Form1.cs and Form1.designer.cs. You write your code in Form1.cs. The designer.cs file is where the Windows Forms Designer writes the code that implements all the actions that you performed by dragging and dropping controls from the Toolbox. For more information about the Windows Forms Designer in Visual C# 2005, visit the following Microsoft Web site:

Note that this solution is available only for output on the screen. To draw reversible lines on a graphics object, you need to 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 kdgdip kbdrawing kbgdipvector

Keywords: kbdswgdi2003swept kbgdi kbhowtomaster KB314945