Archives for: August 2005, 26

26/08/05

Permalink 07:14:28 pm
Categories: General, Programming, .NET

Drawing a selection rubber band like Explorer - improved

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 :-)

This is what things look like before and after my changes:

Here's the complete code again, which will need the same changes as before if it is to be used in VS 2003 (see the comments on the first post for this).

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( ) {
			InitializeComponent( );
			BackColor = Color.White;
		}

		protected override void OnPaint(PaintEventArgs e) {
			if (selectionPanel == null) {
				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);
			}
		}

		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;

			Bitmap contentBitmap = new Bitmap(Bounds.Width, Bounds.Height);
			Rectangle targetRect = Bounds;
			targetRect.X = 0 ;
			targetRect.Y = 0;
			DrawToBitmap(contentBitmap, targetRect);

			Point originScreen = PointToScreen(new Point(0, 0));
			Rectangle usableRect = new Rectangle(new Point(originScreen.X - Bounds.X, originScreen.Y - Bounds.Y), ClientRectangle.Size);
			
			selectionPanel = new SelectionPanel(contentBitmap, usableRect, mouseDownPos);
			Controls.Add(selectionPanel);
			selectionPanel.BringToFront( );
		}

		SelectionPanel selectionPanel;

		protected override void OnMouseMove(MouseEventArgs e) {
			base.OnMouseMove(e);
			if (e.Button == MouseButtons.Left && mouseDownPos != Point.Empty && selectionPanel != null)
				selectionPanel.Invalidate( );
		}

		protected override void OnMouseUp(MouseEventArgs e) {
			base.OnMouseUp(e);
			mouseDownPos = Point.Empty;
			Controls.Remove(selectionPanel);
			selectionPanel = null;
		}

		private Button button1;

		private void InitializeComponent( ) {
			this.button1 = new System.Windows.Forms.Button( );
			this.SuspendLayout( );
			// 
			// button1
			// 
			this.button1.Location = new System.Drawing.Point(114, 108);
			this.button1.Name = "button1";
			this.button1.Size = new System.Drawing.Size(75, 33);
			this.button1.TabIndex = 0;
			this.button1.Text = "button1";
			// 
			// Form1
			// 
			this.ClientSize = new System.Drawing.Size(292, 266);
			this.Controls.Add(this.button1);
			this.Name = "Form1";
			this.ResumeLayout(false);

		}
	}

	public class SelectionPanel : Panel {
		public SelectionPanel(Bitmap backgroundBitmap, Rectangle usableRect, Point mouseDownPos) {
			DoubleBuffered = true;

			this.backgroundBitmap = backgroundBitmap;
			this.mouseDownPos = mouseDownPos;
			this.usableRect = usableRect;

			this.Size = usableRect.Size;
			this.Location = new Point(0, 0);

			selectionColor = Color.FromArgb(200, 0xE8, 0xED, 0xF5);
			selectionBrush = new SolidBrush(selectionColor);
			frameColor = Color.FromArgb(0x33, 0x5E, 0xA8);
			framePen = new Pen(frameColor);
		}

		Bitmap backgroundBitmap;
		Point mouseDownPos;
		Color selectionColor;
		Brush selectionBrush;
		Color frameColor;
		Pen framePen;
		Rectangle usableRect;

		protected override void OnPaint(PaintEventArgs e) {
			// copy the backgroundImage
			e.Graphics.DrawImage(backgroundBitmap, ClientRectangle, usableRect, GraphicsUnit.Pixel);

			// 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);
			}
		}
	}
}
Permalink 01:40:34 pm
Categories: General, Programming, .NET

Drawing a selection rubber band like Explorer

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( );
		}
	}
}

Enter your email address:

Search

Oliver
MVP logo
August 2005
Sun Mon Tue Wed Thu Fri Sat
 << < Current> >>
  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