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 topSample 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:
- Click Project, and then click <ProjectName> Properties.
Note <ProjectName> is a placeholder for the name of the project. - Expand Configuration Properties, and then click General.
- 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:
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