Answered by:
Creating mouse drag box

Question
-
Hi,
Im trying to find out how to reproduce the "box" that appears when a user clicks and holds down the mouse on the windows desktop, and drags the mouse.
Is there an inbuilt event within C# to reproduce this?
Regards,
Gareth.Wednesday, May 23, 2007 7:37 AM
Answers
-
This is actually pretty hard to do in Windows Forms, you can't paint the rectangle properly when it crosses controls. The trick is to create a transparent form that acts as an overlay of the form you want to draw the rectangle on. Here's an example. Add a new class to your project and paste this code:
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
public static class RectangleDrawer {
private static Form mMask;
private static Point mPos;
public static Rectangle Draw(Form parent) {
// Record the start point
mPos = parent.PointToClient(Control.MousePosition);
// Create a transparent form on top of <frm>
mMask = new Form();
mMask.FormBorderStyle = FormBorderStyle.None;
mMask.BackColor = Color.Magenta;
mMask.TransparencyKey = mMask.BackColor;
mMask.ShowInTaskbar = false;
mMask.StartPosition = FormStartPosition.Manual;
mMask.Size = parent.ClientSize;
mMask.Location = parent.PointToScreen(Point.Empty);
mMask.MouseMove += MouseMove;
mMask.MouseUp += MouseUp;
mMask.Paint += PaintRectangle;
mMask.Load += DoCapture;
// Display the overlay
mMask.ShowDialog(parent);
// Clean-up and calculate return value
mMask.Dispose();
mMask = null;
Point pos = parent.PointToClient(Control.MousePosition);
int x = Math.Min(mPos.X, pos.X);
int y = Math.Min(mPos.Y, pos.Y);
int w = Math.Abs(mPos.X - pos.X);
int h = Math.Abs(mPos.Y - pos.Y);
return new Rectangle(x, y, w, h);
}
private static void DoCapture(object sender, EventArgs e) {
// Grab the mouse
mMask.Capture = true;
}
private static void MouseMove(object sender, MouseEventArgs e) {
// Repaint the rectangle
mMask.Invalidate();
}
private static void MouseUp(object sender, MouseEventArgs e) {
// Done, close mask
mMask.Close();
}
private static void PaintRectangle(object sender, PaintEventArgs e) {
// Draw the current rectangle
Point pos = mMask.PointToClient(Control.MousePosition);
using (Pen pen = new Pen(Brushes.Black)) {
pen.DashStyle = DashStyle.Dot;
e.Graphics.DrawLine(pen, mPos.X, mPos.Y, pos.X, mPos.Y);
e.Graphics.DrawLine(pen, pos.X, mPos.Y, pos.X, pos.Y);
e.Graphics.DrawLine(pen, pos.X, pos.Y, mPos.X, pos.Y);
e.Graphics.DrawLine(pen, mPos.X, pos.Y, mPos.X, mPos.Y);
}
}
}
Use it like this:
private void Form1_MouseDown(object sender, MouseEventArgs e) {
Rectangle rc = RectangleDrawer.Draw(this);
Console.WriteLine(rc.ToString());
}Wednesday, May 23, 2007 2:52 PM
All replies
-
This is actually pretty hard to do in Windows Forms, you can't paint the rectangle properly when it crosses controls. The trick is to create a transparent form that acts as an overlay of the form you want to draw the rectangle on. Here's an example. Add a new class to your project and paste this code:
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
public static class RectangleDrawer {
private static Form mMask;
private static Point mPos;
public static Rectangle Draw(Form parent) {
// Record the start point
mPos = parent.PointToClient(Control.MousePosition);
// Create a transparent form on top of <frm>
mMask = new Form();
mMask.FormBorderStyle = FormBorderStyle.None;
mMask.BackColor = Color.Magenta;
mMask.TransparencyKey = mMask.BackColor;
mMask.ShowInTaskbar = false;
mMask.StartPosition = FormStartPosition.Manual;
mMask.Size = parent.ClientSize;
mMask.Location = parent.PointToScreen(Point.Empty);
mMask.MouseMove += MouseMove;
mMask.MouseUp += MouseUp;
mMask.Paint += PaintRectangle;
mMask.Load += DoCapture;
// Display the overlay
mMask.ShowDialog(parent);
// Clean-up and calculate return value
mMask.Dispose();
mMask = null;
Point pos = parent.PointToClient(Control.MousePosition);
int x = Math.Min(mPos.X, pos.X);
int y = Math.Min(mPos.Y, pos.Y);
int w = Math.Abs(mPos.X - pos.X);
int h = Math.Abs(mPos.Y - pos.Y);
return new Rectangle(x, y, w, h);
}
private static void DoCapture(object sender, EventArgs e) {
// Grab the mouse
mMask.Capture = true;
}
private static void MouseMove(object sender, MouseEventArgs e) {
// Repaint the rectangle
mMask.Invalidate();
}
private static void MouseUp(object sender, MouseEventArgs e) {
// Done, close mask
mMask.Close();
}
private static void PaintRectangle(object sender, PaintEventArgs e) {
// Draw the current rectangle
Point pos = mMask.PointToClient(Control.MousePosition);
using (Pen pen = new Pen(Brushes.Black)) {
pen.DashStyle = DashStyle.Dot;
e.Graphics.DrawLine(pen, mPos.X, mPos.Y, pos.X, mPos.Y);
e.Graphics.DrawLine(pen, pos.X, mPos.Y, pos.X, pos.Y);
e.Graphics.DrawLine(pen, pos.X, pos.Y, mPos.X, pos.Y);
e.Graphics.DrawLine(pen, mPos.X, pos.Y, mPos.X, mPos.Y);
}
}
}
Use it like this:
private void Form1_MouseDown(object sender, MouseEventArgs e) {
Rectangle rc = RectangleDrawer.Draw(this);
Console.WriteLine(rc.ToString());
}Wednesday, May 23, 2007 2:52 PM -
Hello
I'm using this transparent overlay solution and it works very well, except for one slight hitch - while the transparent overlay is displayed the main form becomes inactive, so the text in the titlebar is greyed out etc. It would be great if the main form could look as though its still active - is there any way to do this?
Thanks
DominicSunday, May 24, 2009 7:53 AM -
For anyone who's interested, the solution was given in this threadTuesday, May 26, 2009 8:52 AM