Please click this logo to help me get on their beta program:

Xobni outlook add-in for your inbox








26/8/2005

Drawing a selection rubber band like Explorer

Filed under: General, Programming, .NET — Oliver Sturm @ 1:40 pm - 3 years, 1 month ago

I saw the question coming up in a newsgroup today: how do you draw a selection rubber band just like the one Explorer uses, in C#? The first thing that came to mind was the ControlPaint.DrawReversibleFrame() method, but that’s rather restricted. It’s fine to draw a rectangle around an area to select, but it can’t do anything more than that and it also has problems because it draws over windows that are supposed to be in front of the current app window.

Here are screenshots of a selection made in Explorer and a selection made in my sample program. Nice, huh? :-)

So, here’s the code. I created this in VS 2005 beta 2, but I don’t think I used any .NET 2 specific things - if you find any, let me know. To use the sample, just create a new project and replace your newly created Form1 mainform by this code (and throw away the .Designer.cs and resource files).

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
	
namespace SelectionRectTest {
	public class Form1 : Form {
		public Form1( ) {
			DoubleBuffered = true;
			BackColor = Color.White;
	
			selectionColor = Color.FromArgb(200, 0xE8, 0xED, 0xF5);
			selectionBrush = new SolidBrush(selectionColor);
			frameColor =  Color.FromArgb(0x33, 0x5E, 0xA8);
			framePen = new Pen(frameColor);
		}
	
		Color selectionColor;
		Brush selectionBrush;
		Color frameColor;
		Pen framePen;
	
		protected override void OnPaint(PaintEventArgs e) {
			e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
	
			// Draw some stuff so the transparent selection becomes visible
			int height = ClientRectangle.Height;
			int heightTenth = height / 10;
			int width = ClientRectangle.Width;
			int widthTenth = width / 10;
	
			e.Graphics.DrawLines(Pens.Red, new Point[] {
				new Point(widthTenth, heightTenth * 3),
				new Point(widthTenth * 5, heightTenth),
				new Point(widthTenth * 8, heightTenth * 9),
				new Point(widthTenth, heightTenth * 3)
			});
			e.Graphics.DrawEllipse(Pens.Blue, widthTenth * 4, heightTenth * 3, widthTenth * 5, heightTenth * 4);
	
			// Now, if needed, draw the selection rectangle
			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));
				e.Graphics.FillRectangle(selectionBrush, selectedRect);
				e.Graphics.DrawRectangle(framePen, selectedRect);
			}
		}
	
		protected override void OnResize(EventArgs e) {
			base.OnResize(e);
			Invalidate( );
		}
	
		Point mouseDownPos = Point.Empty;
	
		protected override void OnMouseDown(MouseEventArgs e) {
			base.OnMouseDown(e);
	
			if (e.Button == MouseButtons.Left)
				mouseDownPos = e.Location;
		}
	
		protected override void OnMouseMove(MouseEventArgs e) {
			base.OnMouseMove(e);
			if (e.Button == MouseButtons.Left && mouseDownPos != Point.Empty)
				Invalidate( );
		}
	
		protected override void OnMouseUp(MouseEventArgs e) {
			base.OnMouseUp(e);
			mouseDownPos = Point.Empty;
			Invalidate( );
		}
	}
}

7 Comments »

  1. The following lines needed changing for VS 2003:

    /* using System.Collections.Generic; */ using System.Collections;
    /* DoubleBuffered = true; */ SetStyle(ControlStyles.DoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true);
    /* e.Location; */ mouseDownPos = new Point(e.X, e.Y);
    

    And you have to add a Program.cs to the project:

    using System;
    using System.Windows.Forms;
    	
    namespace SelectionRectTest
    {
      class Program
      {
        [STAThread]
        static public void Main(string[] args) {
          Application.Run(new Form1());
        }
      }
    }
    

    Comment by Larry — 26/8/2005 @ 3:57 pm - 3 years, 1 month ago

  2. Larry, you are of course correct. It’s unbelievable how many details there are that are easily overlooked after using VS 2005 for a long while :-) Thanks for pointing this out.

    Comment by Oliver Sturm — 26/8/2005 @ 4:22 pm - 3 years, 1 month ago

  3. Also, you must add the following line as the first line of the Form1 constructor:


          InitializeComponent();

    Probably caused by the partial classes in VS 2005.

    Comment by Larry — 26/8/2005 @ 4:33 pm - 3 years, 1 month ago

  4. No, that’s not right. You don’t need that because the class is a complete derived form in it’s own right. You need that only if you are going to design the class in VS, which you might do in a real-world app, but which is not intended for the sample.

    Comment by Oliver Sturm — 26/8/2005 @ 4:36 pm - 3 years, 1 month ago

  5. But, that’s exactly what I was doing - designing it in VS 2003.

    I added a StatusBar to show the selection rectangle - live!

    Without the InitializeComponent(), my new StatusBar was not being instantiated.

    Thanks for the sample.

    Comment by Larry — 26/8/2005 @ 4:41 pm - 3 years, 1 month ago

  6. True. I meant that you don’t need the InitializeComponent to get my sample to work. I don’t care what else you do with your own copy of it :-)

    Comment by Oliver Sturm — 26/8/2005 @ 4:42 pm - 3 years, 1 month ago

  7. […] I heard criticism about my first post on the topic: if a control was on the form, apart from the background drawing, the rubber rectangle would appear behind the control, not in front of it. Of course there are several ways to change this, I decided to implement one of them just for fun […]

    Pingback by Oliver Sturm’s weblog - Drawing a selection rubber band like Explorer - improved — 26/8/2005 @ 7:22 pm - 3 years, 1 month ago

RSS feed for comments on this post. TrackBack URI

Leave a comment

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>


Powered by WordPress
© Copyright 2005-2008 Oliver Sturm