Moving a drawn line with the mouse

来源:互联网 发布:淘宝怎么做直通车引流 编辑:程序博客网 时间:2024/05/17 03:42

I am trying to move a drawn line by grabbing it with the mouse.


The line have already been drawn with Graphics.DrawLine(Pen P, Point A, Point B).


There is absolutely no problems with creating the Line and drawing it on the form.


I've tried:


Adding the line to a GraphicsPath - This does not even draw the line OnPaint.

Checking if MouseEventArgs e.Location is on the line with some basic algebra (calculations which I have thrown away as of now)

So to sum it up: I want to grab the line and drag it somewhere but I can't even check if e.Location even is on the Line, how do I do this?


EDIT: This is how the code looks when I'm using the GraphicsPath.


When I don't use the GraphicsPath I have:


if (s.thisShape == ShapeType.Line) {

  g.DrawLine(pen, s.p1, s.p2);

} else { ... }`

in the drawingShapes method.


From the drawStuff : Usercontrol class:


private void drawStuff_MouseDown(object sender, MouseEventArgs e)

{

  pointRegion = e.Location;

  for (int i = 0; i < Shapes.Count; i++)

  {

    if (Shapes[i].Region.IsVisible(pointRegion))

    {

      isDragging = true;

      count = i;

      break;

    }

  }

}


private void drawStuff_MouseMove(object sender, MouseEventArgs e)

{

  if (isDragging)

  {

    Shapes[count].moveWithDiff(pointRegion, e.Location);

    pointRegion = e.Location;

    Refresh();

  }

}


private void drawStuff_MouseUp(object sender, MouseEventArgs e)

{

  isDragging = false;

  Refresh();

}


protected override void OnPaint(PaintEventArgs e)

{

  base.OnPaint(e);

  drawShapes(e.Graphics);

}


private void drawShapes(Graphics g)

{

  temporaryPen = pennaLeft;

  foreach (Shape s in Shapes)

  {

    g.FillRegion(temporaryPen, s.Region);

  }

}

From the Shape : Usercontrol class:


public void moveWithDiff(Point pr, Point mp)

{

  Point p = new Point();

  if (this.thisShape == ShapeType.Line)

  {

    p.X = mp.X - pr.X;

    p.Y = mp.Y - pr.Y;

    this.p1.X += p.X;

    this.p1.Y += p.Y;

    this.p2.X += p.X;

    this.p2.Y += p.Y;

  }

  RefreshPath();

}


private void RefreshPath()

{

  gPath = new GraphicsPath();

  switch (thisShape)

  {

    case ShapeType.Line:

      gPath.AddLine(this.p1, this.p2);

      break;

  }

  this.Region = new Region(gPath);

}

Now this doesn't even draw the line, however with said if statement in drawingShapes() It draws perfectly but I can not drag it somewhere else.


2 Answers:

Let's start with the basics, getting a line on the screen. I created a custom class to handle some of the functions I want available to me for this process:


public class MyLine

{

    public Pen pen { get; set; }

    public Point Start { get; set; }

    public Point End { get; set; }


    public MyLine(Pen p, Point p1, Point p2)

    {

        pen = p;

        Start = p1;

        End = p2;

    }


    public float slope

    {

        get

        {

            return (((float)End.Y - (float)Start.Y) / ((float)End.X - (float)Start.X));

        }

    }

    public float YIntercept

    {

        get

        {

            return Start.Y - slope*Start.X;

        }

    }


    public bool IsPointOnLine(Point p, int cushion)

    {

        float temp = (slope * p.X + YIntercept);

        if (temp >= (p.Y-cushion) && temp <=(p.Y+cushion))

        {

            return true;

        }

        else

        {

            return false;

        }

    }

}


This class provides a few helper functions that will make our life easier. We have properties that return the slope and the Y-intercept, so we can determine if a certain point is on the line. We then provide a helper function IsPointOnLine() that takes a point and a cushion. The cushion is used to simply allow for a user to click close enough to the line to get it to return true.

Next I am going to instantiate the line and draw it in the Form's paint event:


MyLine m;


private void Form1_Load(object sender, EventArgs e)

{

    m= new MyLine(Pens.Black, new Point(20, 20), new Point(40, 40));

}


private void Form1_Paint(object sender, PaintEventArgs e)

{

    e.Graphics.DrawLine(m.pen, m.Start, m.End);     

}


Now you should be able to run your application and see a line that goes from 20,20 to 40,40 on the screen.

Now I want to handle the mouse interaction with the line, so on MouseDown, we will see if the click point intersects the line and if it is set a flag and keep our deltas from the endpoints. On the MouseMove event, we will see if the line has been clicked but not released and reset the coordinates appropriately. In the MouseUp event, we simple reset our flag:


Point deltaStart;

Point deltaEnd;

bool dragging = false;


private void Form1_MouseDown(object sender, MouseEventArgs e)

{


    if (e.Button == System.Windows.Forms.MouseButtons.Left && m.IsPointOnLine(e.Location, 5))

    {

        dragging = true;

        deltaStart = new Point(m.Start.X - e.Location.X, m.Start.Y - e.Location.Y);

        deltaEnd = new Point(m.End.X - e.Location.X, m.End.Y - e.Location.Y);

    }

}


private void Form1_MouseMove(object sender, MouseEventArgs e)

{

    if (dragging && deltaStart != null && deltaEnd != null )

    {

        m.Start = new Point(deltaStart.X + e.Location.X, deltaStart.Y + e.Location.Y);

        m.End = new Point(deltaEnd.X + e.Location.X, deltaEnd.Y + e.Location.Y);

        this.Refresh();

    }

}


private void Form1_MouseUp(object sender, MouseEventArgs e)

{

    dragging = false;

}


Now you should be able to click within 5 pixels of the line and have it move with your mouse.

Note, there are some spots in the code that need additional error handling, especially to handle division by 0 errors.


I suggest you create a rectangle that is the width of the line and the length of the line, then you can use


if(rectangle.Contains(Point p))

{

   // do your move

}

You can also inflate the rectangle to make it easier to grab with:


rectangle.Inflate(1, 1);


0 0
原创粉丝点击