« Firefox 2.0 RC - the thing with the tabsCould not find installable ISAM... my a*$% »

Drawing a selection rubber band, take 3

13/10/06

Permalink 07:22:24 pm
Categories: General, Programming, .NET

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!

Rubberband-demo-3

Update: As requested, I’m making the complete sample project available. Here’s the download.

2 comments

Comment from: Rick Engle Email
Oliver, that is impressive! Can you post the project?
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
10/13/06 @ 19:59
I just made the download available from the article above (right at the bottom). I'll look into your other suggestions :-)
10/14/06 @ 17:40

Leave a comment


Your email address will not be revealed on this site.

Your URL will be displayed.
(Line breaks become <br />)
(Name, email & website)
(Allow users to contact you through a message form (your email will not be revealed.)
Please complete the song title below. Hint: enter 'h', 'e', 'a', 'v', 'e', 'n'
antispam test

Enter your email address:

Search

Oliver
MVP logo
July 2010
Sun Mon Tue Wed Thu Fri Sat
 << <   > >>
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31