【问题标题】:Moving a drawn line with the mouse用鼠标移动画线
【发布时间】:2011-12-09 16:08:12
【问题描述】:

我正在尝试通过用鼠标抓住一条画线来移动它。

这条线已经用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:用户控件类:

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

现在这甚至没有画线,但是在 drawingShapes() 中说 if 语句它画得很完美,但我不能把它拖到其他地方。

【问题讨论】:

  • @HansPassant 我编辑了这个问题,我希望这是足够的。现在这与矩形和椭圆等其他形状完美配合,它不会移动线条,更不用说绘制它们了。

标签: c# winforms drag-and-drop line


【解决方案1】:

让我们从基础开始,在屏幕上画一条线。我创建了一个自定义类来处理我希望在此过程中可用的一些功能:

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。

接下来我将实例化线条并在Form的paint事件中绘制它:

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 错误。

【讨论】:

  • 只需对我的程序进行少量改动即可完美运行!谢谢! :)
  • 非常好的解决方法,但是如果要画几条线,你会如何拖动它们?
【解决方案2】:

我建议你创建一个矩形,它是线条的宽度和线条的长度,然后你可以使用

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

您还可以使矩形膨胀以使其更容易抓取:

rectangle.Inflate(1, 1);

【讨论】:

    猜你喜欢
    • 2012-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多