简体   繁体   中英

How to draw a Rectangle in any direction after MouseDown using C#?

How can I draw a rectangle in all directions? Current code:

private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
    // Starting point of the selection:
    if (e.Button == MouseButtons.Left)
    {
        _selecting = true;
        _selection = new Rectangle(new Point(e.X, e.Y), new Size());
    }
}

private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
    // Update the actual size of the selection:
    if (_selecting)
    {
        _selection.Width = e.X - _selection.X;
        _selection.Height = e.Y - _selection.Y;
        pictureBox1.Refresh(); // redraw picturebox

    }
}

private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left && _selecting)
    {
        _selecting = false;
    }
}

This allows me to MouseDown and then draw down and to the right, but I am unable to draw in any other direction beyond the anchor point. How can I draw a rectangle in any direction like eg Microsoft Paint?

在此处输入图片说明

I first tried:

_selection.Width = Math.Abs(e.X - _selection.X);
_selection.Height = Math.Abs(e.Y - _selection.Y);

But this creates a funny mirror effect (which is not what I want). I then tried a simple shift:

_selection.X = _selection.Left - 5;

This did what I expected and moved a static rectangle 5 units left, so I thought it would be a simple matter of continuously shifting the anchor point during the Paint event:

private void UpdateRectange(Point newPos)
{
    var width = newPos.X - _selection.X;
    var height = newPos.Y - _selection.Y;
    _selection.Width = Math.Abs(width);
    _selection.Height = Math.Abs(height);
    if (width < 0 && height > 0) // move down (+) and left (-)
    {
        //_selection.X = _selection.Left + width;
        _selection.Offset(width, 0);
    }
    uxScreenGrab.Refresh(); // redraw picturebox
}

But this resulted in pushing a vertical line across the screen towards the left, when moving to the left of the original anchor point.The width does not properly update for some reason.

在此处输入图片说明

The solution proposed in the question looks good:

_selection.Width = Math.Abs(e.X - initiallySelectedX);
_selection.Height = Math.Abs(e.Y - initiallySelectedY);

...but You have to move the origin of the rectangle when (eX - initiallySelectedX) < 0

So probably You want to add something like this to Your code:

var diffX = e.x - initiallySelectedX;
if (diffX < 0) _selection.X = initiallySelectedX - diffX;
var diffY = e.y - initiallySelectedY;
if (diffY < 0) _selection.Y = initiallySelectedY - diffY;

Where initiallySelectedX and initiallySelectedY are variables set onMouseDown . this is only a rough idea. The idea behind is that the Width and Height of the Rectangle cannot be NEGATIVE !!

Here's another snippet to draw a selection rectangle on a PictureBox :

//...
private Point startPoint;
private Point endPoint;
private readonly Pen P1 = new Pen(Color.SteelBlue, 2) {
    Alignment = PenAlignment.Center, DashStyle = DashStyle.Dash};
//...

Set the startPoint in the MouseDown event and reset the endPoint variables:

private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
        startPoint = new Point(e.X, e.Y);
        endPoint = Point.Empty;
    }
}

Set the endPoint and call Invalidate() method in the MouseMove event:

private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
    var p = new Point(e.X, e.Y);

    if (e.Button == MouseButtons.Left &&
        !p.Equals(startPoint))
    {
        endPoint = p;
        pictureBox1.Invalidate();
    }
}

Also call Invalidate() in the MouseUp event to remove the selection rectangle:

private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
    pictureBox1.Invalidate();
}

Draw the selection rectangle:

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
    if(MouseButtons == MouseButtons.Left &&
        !startPoint.Equals(endPoint) &&
        !endPoint.Equals(Point.Empty))
    {
        var g = e.Graphics;
        var rect = Rectangle.Empty;

        if(startPoint.X < endPoint.X)
        {
            rect.X = startPoint.X;
            rect.Width = endPoint.X - startPoint.X;
        }
        else
        {
            rect.X = endPoint.X;
            rect.Width = startPoint.X - endPoint.X;
        }
        if(startPoint.Y < endPoint.Y)
        {
            rect.Y = startPoint.Y;
            rect.Height = endPoint.Y - startPoint.Y;
        }
        else
        {
            rect.Y = endPoint.Y;
            rect.Height = startPoint.Y - endPoint.Y;
        }
        g.DrawRectangle(P1, rect);
    }
}

And don't forget to clean up:

private void YourForm_FormClosing(object sender, FormClosingEventArgs e)
{
    P1.Dispose();
}

Keep it simple.

SOQ60022534

Related Posts

How to call a method that uses PaintEventArgs and coordinates variables

UPDATE:

Keeping track of the starting point on the MouseDown event allows the anchor point to correctly update:

private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
    // Starting point of the selection:
    if (e.Button == MouseButtons.Left)
    {
        _selecting = true;
        _selection = new Rectangle(new Point(e.X, e.Y), new Size());
        _startingPoint = e.Location;
    }
}

private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
    // Update the actual size of the selection:
    if (_selecting)
    {
        UpdateRectange(e.Location);
    }
}

private void UpdateRectange(Point newPos)
{
    var diffX = newPos.X - _startingPoint.X;
    var diffY = newPos.Y - _startingPoint.Y;
    var newSize = new Size(Math.Abs(diffX), Math.Abs(diffY));
    if (diffX > 0 && diffY > 0)
    {
        _selection = new Rectangle(_startingPoint, newSize);
    }
    else if (diffX < 0 && diffY < 0)
    {
        _selection = new Rectangle(newPos, newSize);
    }
    else if (diffX > 0 && diffY < 0)
    {
        _selection = new Rectangle(new Point(_startingPoint.X, _startingPoint.Y + diffY), newSize);
    }
    else
    {
        _selection = new Rectangle(new Point(_startingPoint.X + diffX, _startingPoint.Y), newSize);
    }
    uxScreenGrab.Invalidate();
}

UPDATE 2:

Re-wrote UpdateRectangle to simply move the anchor point, instead of instantiating at every call:

private void UpdateRectange(Point newPos)
{
    var diffX = newPos.X - _startingPoint.X;
    var diffY = newPos.Y - _startingPoint.Y;
    var newSize = new Size(Math.Abs(diffX), Math.Abs(diffY));
    if (diffX > 0 && diffY > 0)
    {
        _selection.Size = newSize;
    }
    else if (diffX < 0 && diffY < 0)
    {
        _selection.Location = newPos;
        _selection.Size = newSize;
    }
    else if (diffX > 0 && diffY < 0)
    {
        _selection.Y = _startingPoint.Y + diffY;
        _selection.Size = newSize;
    }
    else
    {
        _selection.X = _startingPoint.X + diffX;
        _selection.Size = newSize;
    }
    uxScreenGrab.Invalidate();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM