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 on Drawing a selection rubber band, take 3

  1. 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

    Like

  2. I just made the download available from the article above (right at the bottom). I’ll look into your other suggestions 🙂

    Like

Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s