问题描述
在C#WindoeFormsApplication中,是否可以选择,从而用鼠标移动或删除绘制的形状?像Windows画图程序一样。
In a C# WindoeFormsApplication, is it possible to select, hence to move or delete a plotted shape with mouse? Like the windows paint program.
图形绘制完全正常,所有点都存储在某个数组中。作为此线条图示例
The shape plotting works totally fine, all points are stored in some array. As this line drawing example
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();
}
我可以让它计算鼠标位置和每行之间的最短距离,方法是基本线性代数,并设置一个阈值距离(如果它小于阈值),请选择此线,并可以用鼠标拖动或编辑。但是,我只是想知道,对于这种任务,还有什么方法更容易管理吗?主要是选择部分。
任何建议将不胜感激,谢谢!!
I can let it to calculate the shortest distance between mouse position and each line by basic linear algebra, and set a threshold distance, if it's shorter than the threshold, make this line selected, and can be dragged or edited by mouse. But, just wondering, is there any way that's more manageable for such task? Mainly the selection part.Any suggestion will be appreciated, thank you!
推荐答案
要达到测试形状,您不需要线性代数。您可以为形状创建 GraphicsPath
,然后使用方法或方法执行点击测试。
To hit test shapes you don't need linear algebra. You can create GraphicsPath
for your shapes and then using GraphicsPath.IsVisible
method or GraphicsPath.IsOutlineVisible
method perform hit-testing.
-
要检查路径中是否有点(例如填充的形状),请使用
IsVisible
。
要测试线条或曲线或空形状,可以使用 IsOutlineVisible
。
To hit-test for lines or curves or empty shapes, you can use IsOutlineVisible
.
作为示例,您可以创建基础 IShape
界面,其中包含命中测试,绘图和移动的方法。然后在类中实现这些方法。您还可以创建一个 DrawingSurface
控件,该控件可以进行命中测试,绘制和移动 IShape
对象。
As an example, you can create a base IShape
interface that contains methods for hit-testing, drawing and moving. Then in classes implement those methods. Also you can create a DrawingSurface
control which can handle hit-testing, drawing and moving IShape
objects.
在下面的示例中,我们创建 IShape
接口, Line
和 Circle
类。同样,我们创建一个 DrawingSurface
控件。为了测试该示例,足以将 DrawingSurface
控件放在 Form
上并处理 Load
事件,添加一些形状,然后运行应用程序并尝试移动形状。
In the below example, we create IShape
interface, Line
and Circle
classes. Also we create a DrawingSurface
control. To test the example, its enough to put a DrawingSurface
control on a Form
and handle Load
event of form and add some shapes, then run application and try to move shapes.
IShape
此接口包含一些有用的方法,如果有任何类可以实现这些方法,则可以用于绘图,命中测试和移动。在此示例的最后,您可以看到一个 DrawingSurface
控件,该控件可以简单地与 IShape
实现一起使用:
This interface contains some useful methods which if any class implements them, can be used for drawing, hit-testing and moving. At the end of this example, you can see a DrawingSurface
control which can work with IShape
implementations simply:
public interface IShape
{
GraphicsPath GetPath();
bool HitTest(Point p);
void Draw(Graphics g);
void Move(Point d);
}
Line
此处是实现 IShape
接口的线型。如果单击行进行命中测试,则 HitTest
返回true。为了让您更简单地选择行,我为命中测试添加了2分:
Here is a line class which implements IShape
interface. When hit-testing if you click on line, the HitTest
returns true. Also to let you choose line more simply, I added 2 points for hit-testing:
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
接口的圈子类。在点击圆形测试时, HitTest
返回true:
Here is a circle class which implements IShape
interface. When hit-testing if you click in circle, the HitTest
returns 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);
}
}
DrawingSurface
该控件绘制形状列表。它还在 MouseDown
中执行命中测试,并在拖动形状时移动形状。您应该在 Shape
中添加一些形状,例如 Line
或 Circle
The control, draws a list of shapes. Also it performs hit-testing in MouseDown
and moves the shape if you drag it. You should add some shapes like Line
or Circle
to Shapes
collection of the control.
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#中拖动和移动形状的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!