简体   繁体   中英

Using Matrix.Rotate more than once C# Winforms

I've been trying to solve a problem I'm having with rotating an oval. The code that I'm posting works, but it's mimicking the kind of code I have to work with for real. Meaning, I can't use the OnPaint override and I'm limited to what I can do in the main code. I'm adding an oval to a graphic layer, and I need to be able to rotate, move and resize the oval. Move and resizing work flawlessly, but rotating doesn't work as I need it to. If you click in the small box at the 9 oclock position, 在此处输入图片说明

the oval will rotate as expected: 在此处输入图片说明

The required behavior is to be able to click in the small box at the 12 oclock position, and have the oval rotate again. This does not occur. In order to get the oval to rotate again you need to click in the original 9 oclock position. What I'm really, really trying to find out is how to get the coordinates of the box at the 12 oclock position (or what ever position or location that box ends up after rotating) so that I can rotate it again. Thus far, I have been unable to figure it out. Please try and understand, I'm working with old code that was poorly written and I'm not allowed to change very much of it. What I write must integrate with what's already there. Below is the code snippet that demonstrates what I'm doing. I know I'm missing something obvious, just don't know what. Thanks.

 public partial class Form1 : Form
{
    int theAngle = 0;
    Pen pen2 = new Pen(Color.FromArgb(255, 68, 125, 255), 4);
    Pen pen3 = new Pen(Color.Green, 4);
    Pen smallPen = new Pen(Color.Black, 1);

    PointF center = new PointF(0, 0);
    Rectangle rectangle = new Rectangle(20, 20, 100, 30);
    Rectangle myRect2 = new Rectangle();
    bool mouseBtnDown = false;
    Graphics gw;

    public Form1()
    {
        InitializeComponent();
        this.MouseDown += mouseDown;
        gw = this.CreateGraphics();
    }

    private void mouseDown(object sender, MouseEventArgs e)
    {


        if (e.Button == MouseButtons.Left)
        {

            if (myRect2.Contains(e.Location))
                theAngle+=90;

            rotate();
        }

        if (e.Button == MouseButtons.Right)
        {
            //oval = false;
            //mouseBtnDown = false;
            theAngle = 0;
            rectangle.X = e.X - 50;
            rectangle.Y = e.Y - 15;
            rectangle.Width = 100;
            rectangle.Height = 30;
            center.X = rectangle.Left + (0.5f * rectangle.Width);
            center.Y = rectangle.Top + (0.5f * rectangle.Height);
            myRect2.Size = new Size(15, 15);
            myRect2.Location = new Point(rectangle.Left - 15, (rectangle.Top - (rectangle.Height / 2)) + 15);
            drawstuff();
           // Invalidate();
        }

    } 

     public void rotate()
    {
        var matrix = new Matrix();

        matrix.RotateAt(theAngle, center);
        gw.Transform = matrix;
        drawstuff();
    }
    public void drawstuff()
    {


        gw.SmoothingMode = SmoothingMode.AntiAlias; // Creates smooth lines.
        gw.DrawEllipse(pen2, rectangle);

        gw.DrawRectangle(smallPen, myRect2);
    }
}

You can use the Transform matrix to rotate points. So what I've done is get the 4 corner points of myRect2 , rotate them using the same Transform matrix, then assign these to a rectangle. You can then use this new rectangle to check the location. I also changed the call to drawstuff() at the end of the right button click to call rotate() , this way the rotated rectangle can get updated when the ellipse is first placed, and the graphics transform angle gets updated to 0.

public partial class Form1 : Form
{
  int theAngle = 0;
  Pen pen2 = new Pen(Color.FromArgb(255, 68, 125, 255), 4);
  Pen pen3 = new Pen(Color.Green, 4);
  Pen smallPen = new Pen(Color.Black, 1);

  PointF center = new PointF(0, 0);
  Rectangle rectangle = new Rectangle(20, 20, 100, 30);
  Rectangle myRect2 = new Rectangle();
  Rectangle rotatedRect2 = new Rectangle();
  bool mouseBtnDown = false;
  Graphics gw;

  public Form1()
  {
    InitializeComponent();
    this.MouseDown += mouseDown;
    gw = this.CreateGraphics();
  }


  private void mouseDown(object sender, MouseEventArgs e)
  {
    if (e.Button == MouseButtons.Left)
    {
      if (rotatedRect2.Contains(e.Location))
        theAngle += 90;

      rotate();
    }

    if (e.Button == MouseButtons.Right)
    {
      //oval = false;
      //mouseBtnDown = false;
      theAngle = 0;
      rectangle.X = e.X - 50;
      rectangle.Y = e.Y - 15;
      rectangle.Width = 100;
      rectangle.Height = 30;
      center.X = rectangle.Left + (0.5f * rectangle.Width);
      center.Y = rectangle.Top + (0.5f * rectangle.Height);
      myRect2.Size = new Size(15, 15);
      myRect2.Location = new Point(rectangle.Left - 15, (rectangle.Top - (rectangle.Height / 2)) + 15);
      rotate();
      //drawstuff();
      // Invalidate();
    }
  }

  public void rotate()
  {
    var matrix = new Matrix();

    matrix.RotateAt(theAngle, center);
    gw.Transform = matrix;

    // Get the 4 corner points of myRect2.
    Point p1 = new Point(myRect2.X, myRect2.Y),
      p2 = new Point(myRect2.X + myRect2.Width, myRect2.Y),
      p3 = new Point(myRect2.X, myRect2.Y + myRect2.Height),
      p4 = new Point(myRect2.X + myRect2.Width, myRect2.Y + myRect2.Height);

    Point[] pts = new Point[] { p1, p2, p3, p4 };

    // Rotate the 4 points.
    gw.Transform.TransformPoints(pts);

    // Update rotatedRect2 with those rotated points.
    rotatedRect2.X = pts.Min(pt => pt.X);
    rotatedRect2.Y = pts.Min(pt => pt.Y);
    rotatedRect2.Width = pts.Max(pt => pt.X) - pts.Min(pt => pt.X);
    rotatedRect2.Height = pts.Max(pt => pt.Y) - pts.Min(pt => pt.Y);

    drawstuff();
  }

  public void drawstuff()
  {
    gw.SmoothingMode = SmoothingMode.AntiAlias; // Creates smooth lines.
    gw.DrawEllipse(pen2, rectangle);

    gw.DrawRectangle(smallPen, myRect2);
  }
}

Something to note. Drawing to the screen like this (using the form's created graphics and drawing using your own draw function) means the ellipses/rectangles are only drawn once. ie if you draw a few then minimize your form, when you bring it back up the ellipses will be gone. Not sure if this is what you're after or not. One way to fix this would be to draw the ellipses to a Bitmap and then in the form's Paint event this bitmap is draw to the form.

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