Перемещение нарисованной линии мышью - PullRequest
1 голос
/ 09 декабря 2011

Я пытаюсь переместить нарисованную линию, схватив ее мышью.

Линия уже нарисована с помощью Graphics.DrawLine(Pen P, Point A, Point B).

Нет абсолютно никаких проблем с созданием линиии рисуя его на форме.

Я пробовал:

  • Добавление линии к GraphicsPath - Это даже не рисует линию OnPaint.

  • Проверка, находится ли MouseEventArgs e.Location на линии с некоторой базовой алгеброй (вычисления, которые я отбросил на данный момент)

Так чтоПодводя итог: я хочу взять строку и перетащить ее куда-нибудь, но я даже не могу проверить, есть ли на линии e.Location, как мне это сделать?

РЕДАКТИРОВАТЬ: Вот как кодвыглядит, когда я использую GraphicsPath.

Когда я не использую GraphicsPath, у меня есть:

if (s.thisShape == ShapeType.Line) {
  g.DrawLine(pen, s.p1, s.p2);
} else { ... }`

в методе drawingShapes.

Из drawStuff:Класс usercontrol:

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);
  }
}

Из Shape: класс Usercontrol:

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);
}

Теперь это даже не рисует линию, однако с указаннымОператор if в DrawingShapes () Рисует отлично, но я не могу перетащить его куда-нибудь еще.

Ответы [ 2 ]

7 голосов
/ 09 декабря 2011

Давайте начнем с основ, получая линии на экране.Я создал пользовательский класс для обработки некоторых функций, которые мне нужны для этого процесса:

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;
        }
    }
}

Этот класс предоставляет несколько вспомогательных функций, которые облегчат нашу жизнь.У нас есть свойства, которые возвращают наклон и Y-точку пересечения, поэтому мы можем определить, находится ли определенная точка на линии.Затем мы предоставляем вспомогательную функцию IsPointOnLine (), которая принимает точку и подушку.Подушка используется, чтобы просто позволить пользователю щелкнуть достаточно близко к линии, чтобы она вернула true.

Далее я собираюсь создать экземпляр линии и нарисовать ее в событии рисования формы:

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);     
}

Теперь вы должны иметь возможность запустить ваше приложение и увидеть на экране строку, которая идет от 20,20 до 40,40.

Теперь я хочу обработать взаимодействие мыши со строкойпоэтому в MouseDown мы увидим, пересекает ли точка щелчка линию, и установлен ли флаг, и сохраним наши дельты от конечных точек.В случае MouseMove мы увидим, была ли нажата линия, но не отпущена, и соответствующим образом сбросим координаты.В случае MouseUp мы просто сбрасываем наш флаг:

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;
}

Теперь вы должны иметь возможность щелкнуть в пределах 5 пикселей от линии и заставить его двигаться с помощью мыши.

Обратите внимание, что тамВ коде есть некоторые места, которые требуют дополнительной обработки ошибок, особенно для обработки деления на 0 ошибок.

0 голосов
/ 09 декабря 2011

Я предлагаю вам создать прямоугольник, который является шириной линии и длиной линии, тогда вы можете использовать

if(rectangle.Contains(Point p))
{
   // do your move
}

Вы также можете надуть прямоугольник, чтобы его было легче захватить:

rectangle.Inflate(1, 1);
...