| « Firefox 2.0 RC - the thing with the tabs | Could not find installable ISAM... my a*$% » |
Drawing a selection rubber band, take 3
13/10/06
Drawing a selection rubber band, take 3
In two previous posts (here and here) I have previously posted about how to draw rubber band selection rectangles similar to what Explorer does. Now a reader contacted me by email and asked for an extension: he wants to have a reverse selection, similar to this picture:

So, no problem of course :-) I started out from the improved version of the first demo and made a few changes – all you have to do is replace the SelectionPanel.OnPaint() method with this:
protected override void OnPaint(PaintEventArgs e) {
ColorMatrix colorMatrix = new ColorMatrix(new float[][] {
new float[] {1.0f, 0.0f, 0.0f, 0.0f, 0.0f},
new float[] {0.0f, 1.0f, 0.0f, 0.0f, 0.0f},
new float[] {0.0f, 0.0f, 1.0f, 0.0f, 0.0f},
new float[] {0.0f, 0.0f, 0.0f, 0.3f, 0.0f},
new float[] {0.0f, 0.0f, 0.0f, 0.0f, 1.0f}
});
ImageAttributes imageAttributes = new ImageAttributes( );
imageAttributes.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
Point[] destPoints = new Point[] {
new Point(ClientRectangle.Left, ClientRectangle.Top),
new Point(ClientRectangle.Right, ClientRectangle.Top),
new Point(ClientRectangle.Left, ClientRectangle.Bottom)
};
e.Graphics.DrawImage(backgroundBitmap, destPoints, usableRect, GraphicsUnit.Pixel, imageAttributes);
if (mouseDownPos != Point.Empty) {
Point mousePos = PointToClient(MousePosition);
Rectangle selectedRect = new Rectangle(
Math.Min(mouseDownPos.X, mousePos.X),
Math.Min(mouseDownPos.Y, mousePos.Y),
Math.Abs(mousePos.X - mouseDownPos.X),
Math.Abs(mousePos.Y - mouseDownPos.Y));
Point srcRectLocation = selectedRect.Location;
srcRectLocation.Offset(usableRect.Location);
Rectangle srcRect = new Rectangle(srcRectLocation, selectedRect.Size);
e.Graphics.DrawImage(backgroundBitmap, selectedRect, srcRect, GraphicsUnit.Pixel);
using (Pen pen = new Pen(Color.Black)) {
pen.DashPattern = new float[] { 2f, 2f };
int thirdOfHeight = selectedRect.Height / 3;
int thirdOfWidth = selectedRect.Width / 3;
e.Graphics.DrawRectangle(Pens.White, selectedRect);
e.Graphics.DrawLine(Pens.White, selectedRect.Left, selectedRect.Top + thirdOfHeight, selectedRect.Right, selectedRect.Top + thirdOfHeight);
e.Graphics.DrawLine(Pens.White, selectedRect.Left, selectedRect.Bottom - thirdOfHeight, selectedRect.Right, selectedRect.Bottom - thirdOfHeight);
e.Graphics.DrawLine(Pens.White, selectedRect.Left + thirdOfWidth, selectedRect.Top, selectedRect.Left + thirdOfWidth, selectedRect.Bottom);
e.Graphics.DrawLine(Pens.White, selectedRect.Right - thirdOfWidth, selectedRect.Top, selectedRect.Right - thirdOfWidth, selectedRect.Bottom);
e.Graphics.DrawRectangle(pen, selectedRect);
e.Graphics.DrawLine(pen, selectedRect.Left, selectedRect.Top + thirdOfHeight, selectedRect.Right, selectedRect.Top + thirdOfHeight);
e.Graphics.DrawLine(pen, selectedRect.Left, selectedRect.Bottom - thirdOfHeight, selectedRect.Right, selectedRect.Bottom - thirdOfHeight);
e.Graphics.DrawLine(pen, selectedRect.Left + thirdOfWidth, selectedRect.Top, selectedRect.Left + thirdOfWidth, selectedRect.Bottom);
e.Graphics.DrawLine(pen, selectedRect.Right - thirdOfWidth, selectedRect.Top, selectedRect.Right - thirdOfWidth, selectedRect.Bottom);
}
}
}
The result is this (I got rid of my main form drawing routine and inserted a nice background picture instead). Very nice!

Update: As requested, I’m making the complete sample project available. Here’s the download.
2 comments
In your example is the selection floating over the entire form or can it be contrained to an image? This idea would be to server as a nice way to highlight an image to be clipped. if you loaded an image on a form using GDI would it be hard to restrict the rubberband to only work within the rectangle boundary of the host image?
How hard would it be to have the rubberband image stay up afte you draw it? Ideally you could guess at your selection and then once drawn be able to move and adjust the frame based on handles. I have read that the ControlPaint class has a DrawGrabHandle() method which creates drag handles but its very lightly documented.
I'll keep looking around but ideally I'd take your starting code and build the ability to adjust the size of the frame vertically, horizontally and diagonally as well as be able to rotate it. And then once its positioned and adjusted correctly it would be a powerful tool to be able to precisely clip an image.
Thanks!
Rick


