Microsoft KB Archive/816170

From BetaArchive Wiki
Knowledge Base


How to draw a rubber band or focus rectangle in Visual C++ .NET or in Visual C++ 2005

Article ID: 816170

Article Last Modified on 1/5/2006



APPLIES TO

  • Microsoft Visual C++ 2005 Express Edition
  • Microsoft Visual C++ .NET 2003 Standard Edition
  • Microsoft .NET Framework 1.1




For a Microsoft Visual Basic .NET version of this article, see 317479.

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

This article references the following .NET Framework Class Library namespaces:

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


IN THIS TASK

SUMMARY

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

In the GDI, focus rectangles are frequently 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 remove 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 by using the ControlPaint::DrawReversibleFrame() static member. The following sample code that is written in Visual C++ .NET or in Visual C++ 2005 and ready to paste in the form class in a default Windows Forms Application (.NET), demonstrates this approach:

private:
    bool bHaveMouse;
    System::Drawing::Point ptOriginal; 
    System::Drawing::Point ptLast;

    // Set up delegates for mouse events.
    protected: void OnLoad(System::EventArgs *e)
    {
        MouseDown += new MouseEventHandler( this, MyMouseDown );
        MouseUp += new MouseEventHandler( this, MyMouseUp );
        MouseMove += new MouseEventHandler( this, MyMouseMove );
        bHaveMouse = false;
    }

// Convert and Normalize the points and draw the reversible frame.
private: 
void MyDrawReversibleRectangle(Point p1, Point p2)
{
        Rectangle rc;
           
        // 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 pressed down.
public: 
void MyMouseDown(System::Object *sender, System::Windows::Forms::MouseEventArgs *e) 
    {
        // Make a note that you "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 you know that no previous
        // rectangle must be erased.
        ptLast.X = -1;
        ptLast.Y = -1;
    }

// Called when the left mouse button is released
public: 
void MyMouseUp(System::Object *sender, System::Windows::Forms::MouseEventArgs *e) 
    {
        // Set internal flag to know that you no longer "have the mouse."
        bHaveMouse = false;
            
        // If you have drawn previously, draw again in that spot
        // to remove the lines.
        if (ptLast.X != -1)
        {
            Point ptCurrent;
            ptCurrent.X = e->X;
            ptCurrent.Y = 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(System::Object *sender, System::Windows::Forms::MouseEventArgs *e) 
    {
        Point ptCurrent;
        ptCurrent.X = e->X;
        ptCurrent.Y = e->Y;
           
        // If you "have the mouse," draw your lines.
        if (bHaveMouse) 
        {
            // If you 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);
        }
    }

Note You must add the common language runtime support compiler option (/clr:oldSyntax) in Visual C++ 2005 to successfully compile the previous code sample. To add the common language runtime support compiler option in Visual C++ 2005, follow these steps:

  1. Click Project, and then click <ProjectName> Properties.


Note <ProjectName> is a placeholder for the name of the project.

  1. Expand Configuration Properties, and then click General.
  2. Click to select Common Language Runtime Support, Old Syntax (/clr:oldSyntax) in the Common Language Runtime support project setting in the right pane, click Apply, and then click OK.

For more information about the common language runtime support compiler option, visit the following Microsoft Web site:

/clr (Common Language Runtime Compilation)
http://msdn2.microsoft.com/en-us/library/k8d11d4s.aspx


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

back to the top


Additional query words: Rubberband, Rubber-Band, Rect, Invert, Focus Rectangle, Drawing

Keywords: kbhowtomaster kbgdiplus kbgdi kbforms KB816170