如何在C#中拖动和移动形状

在C#WindoeFormsApplication中,是否可以选择,因此可以使用鼠标移动或删除绘制的形状? 喜欢windows paint程序。

形状绘图完全正常,所有点都存储在一些数组中。 如此线描示例

Point Latest { get; set; } List _points = new List(); protected override void OnMouseMove(MouseEventArgs e) { base.OnMouseMove(e); // Save the mouse coordinates Latest = new Point(eX, eY); // Force to invalidate the form client area and immediately redraw itself. Refresh(); } protected override void OnPaint(PaintEventArgs e) { var g = e.Graphics; base.OnPaint(e); if (_points.Count > 0) { var pen = new Pen(Color.Navy); var pt = _points[0]; for(var i=1; _points.Count > i; i++) { var next = _points[i]; g.DrawLine(pen, pt, next); pt = next; } g.DrawLine(pen, pt, Latest); } } private void Form1_MouseClick(object sender, MouseEventArgs e) { Latest = new Point(eX, eY); _points.Add(Latest); Refresh(); } 

我可以让它通过基本线性代数计算鼠标位置和每条线之间的最短距离,并设置一个阈值距离,如果它短于阈值,则选择该线,并可以通过鼠标拖动或编辑。 但是,只是想知道,有没有什么方法可以更容易管理这样的任务? 主要是选择部分。 任何建议将不胜感激,谢谢!

要命中测试形状,您不需要线性代数。 您可以为形状创建GraphicsPath ,然后使用GraphicsPath.IsVisible方法或GraphicsPath.IsOutlineVisible方法执行命中测试。

  • 要检查点是否在路径区域中,例如填充的形状,请使用IsVisible

  • 要对线条或曲线或空形状进行测试,可以使用IsOutlineVisible

例如,您可以创建一个基本IShape接口,其中包含命中测试,绘图和移动的方法。 然后在类中实现这些方法。 您还可以创建一个DrawingSurface控件,它可以处理命中测试,绘制和移动IShape对象。

在下面的示例中,我们创建了IShape接口, LineCircle类。 我们还创建了一个DrawingSurface控件。 为了测试这个例子,它足以将一个DrawingSurface控件放在Form并处理Form Load事件并添加一些形状,然后运行应用程序并尝试移动形状。

IShape的

该接口包含一些有用的方法,如果任何类实现它们,可以用于绘图,命中测试和移动。 在本示例的最后,您可以看到一个可以简单地使用IShape实现的DrawingSurface控件:

 public interface IShape { GraphicsPath GetPath(); bool HitTest(Point p); void Draw(Graphics g); void Move(Point d); } 

线

这是一个实现IShape接口的行类。 如果点击线路进行点击测试,则HitTest返回true。 另外为了让你更简单地选择线路,我为命中测试增加了2分:

 public class Line : IShape { public Line() { LineWidth = 2; LineColor = Color.Black; } public int LineWidth { get; set; } public Color LineColor { get; set; } public Point Point1 { get; set; } public Point Point2 { get; set; } public GraphicsPath GetPath() { var path = new GraphicsPath(); path.AddLine(Point1, Point2); return path; } public bool HitTest(Point p) { var result = false; using (var path = GetPath()) using (var pen = new Pen(LineColor, LineWidth + 2)) result = path.IsOutlineVisible(p, pen); return result; } public void Draw(Graphics g) { using (var path = GetPath()) using (var pen = new Pen(LineColor, LineWidth)) g.DrawPath(pen, path); } public void Move(Point d) { Point1 = new Point(Point1.X + dX, Point1.Y + dY); Point2 = new Point(Point2.X + dX, Point2.Y + dY); } } 

这是一个实现IShape接口的圆类。 如果点击圈子进行点击测试,则HitTest返回true:

 public class Circle : IShape { public Circle() { FillColor = Color.Black; } public Color FillColor { get; set; } public Point Center { get; set; } public int Radious { get; set; } public GraphicsPath GetPath() { var path = new GraphicsPath(); var p = Center; p.Offset(-Radious, -Radious); path.AddEllipse(pX, pY, 2 * Radious, 2 * Radious); return path; } public bool HitTest(Point p) { var result = false; using (var path = GetPath()) result = path.IsVisible(p); return result; } public void Draw(Graphics g) { using (var path = GetPath()) using (var brush = new SolidBrush(FillColor)) g.FillPath(brush, path); } public void Move(Point d) { Center = new Point(Center.X + dX, Center.Y + dY); } } 

DrawingSurface

控件,绘制一个形状列表。 它还在MouseDown执行命中测试,并在拖动时移动形状。 您应该向控件添加一些形状,如LineCircle to Shapes集合。

 public class DrawingSurface : Control { public List Shapes { get; private set; } IShape selectedShape; bool moving; Point previousPoint = Point.Empty; public DrawingSurface() { DoubleBuffered = true; Shapes = new List(); } protected override void OnMouseDown(MouseEventArgs e) { for (var i = Shapes.Count - 1; i >= 0; i--) if (Shapes[i].HitTest(e.Location)) { selectedShape = Shapes[i]; break; } if (selectedShape != null) { moving = true; previousPoint = e.Location; } base.OnMouseDown(e); } protected override void OnMouseMove(MouseEventArgs e) { if (moving) { var d = new Point(eX - previousPoint.X, eY - previousPoint.Y); selectedShape.Move(d); previousPoint = e.Location; this.Invalidate(); } base.OnMouseMove(e); } protected override void OnMouseUp(MouseEventArgs e) { if (moving) { selectedShape = null; moving = false; } base.OnMouseUp(e); } protected override void OnPaint(PaintEventArgs e) { e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; foreach (var shape in Shapes) shape.Draw(e.Graphics); } }