none
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
    Moderator

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
    Moderator
  • 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
    Dominic
    Sunday, May 24, 2009 7:53 AM
  • For anyone who's interested, the solution was given in this thread
    Tuesday, May 26, 2009 8:52 AM