在 C# WindoeFormsApplication 中,是否可以使用鼠标选择、移动或删除绘制的形状?就像 Windows 绘图程序一样。
形状绘图工作得很好,所有点都存储在某个数组中。正如这个画线示例
Point Latest { get; set; }
List<Point> _points = new List<Point>();
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
// Save the mouse coordinates
Latest = new Point(e.X, e.Y);
// 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(e.X, e.Y);
_points.Add(Latest);
Refresh();
}
我可以让它通过基本线性代数来计算鼠标位置到每条线的最短距离,并设置一个阈值距离,如果短于阈值,则使该线被选中,并且可以通过鼠标拖动或编辑。但是,只是想知道,有没有什么方法可以更轻松地完成此类任务?主要是选择部分。 如有任何建议,我们将不胜感激,谢谢!
最佳答案
要达到测试形状,您不需要线性代数。您可以为您的形状创建GraphicsPath
,然后使用 GraphicsPath.IsVisible
方法或GraphicsPath.IsOutlineVisible
方法执行 HitTest 。
要检查某个点是否位于路径区域(例如填充形状),请使用
IsVisible
。要对直线、曲线或空形状进行 HitTest ,您可以使用
IsOutlineVisible
。
示例
例如,您可以创建一个基本 IShape
接口(interface),其中包含 HitTest 、绘图和移动的方法。然后在类中实现这些方法。您还可以创建一个 DrawingSurface
控件,它可以处理 HitTest 、绘制和移动 IShape
对象。
在下面的示例中,我们创建了 IShape
接口(interface)、Line
和 Circle
类。我们还创建了一个DrawingSurface 控件。要测试示例,只需将 DrawingSurface
控件放在 Form
上并处理表单的 Load
事件并添加一些形状,然后运行应用程序就足够了并尝试移动形状。
IShape
该接口(interface)包含一些有用的方法,如果任何类实现了这些方法,则可用于绘图、 HitTest 和移动。在此示例的末尾,您可以看到一个 DrawingSurface
控件,它可以简单地与 IShape
实现一起使用:
public interface IShape
{
GraphicsPath GetPath();
bool HitTest(Point p);
void Draw(Graphics g);
void Move(Point d);
}
线条
这是一个实现IShape
接口(interface)的线路类。进行 HitTest 时,如果单击该行,HitTest
将返回 true。另外为了让你更简单地选择线路,我添加了 2 个点用于 HitTest :
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 + d.X, Point1.Y + d.Y);
Point2 = new Point(Point2.X + d.X, Point2.Y + d.Y);
}
}
圆圈
这是一个实现IShape
接口(interface)的圆类。进行 HitTest 时,如果单击圆圈,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(p.X, p.Y, 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 + d.X, Center.Y + d.Y);
}
}
绘图表面
该控件绘制形状列表。它还在 MouseDown
中执行点击测试,并在拖动形状时移动形状。您应该将一些形状(例如 Line
或 Circle
)添加到控件的 Shapes
集合中。
public class DrawingSurface : Control
{
public List<IShape> Shapes { get; private set; }
IShape selectedShape;
bool moving;
Point previousPoint = Point.Empty;
public DrawingSurface() { DoubleBuffered = true; Shapes = new List<IShape>(); }
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(e.X - previousPoint.X, e.Y - 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);
}
}
关于c# - 如何在 C# 中拖动和移动形状,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38747027/