如何在 C# 中拖动和移动形状 [英] How to drag and move shapes in C#

查看:49
本文介绍了如何在 C# 中拖动和移动形状的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 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,然后使用 GraphicsPath.IsVisible 方法或 GraphicsPath.IsOutlineVisible 方法执行命中测试.

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 接口、LineCircle 类.我们还创建了一个 DrawingSurface 控件.为了测试这个例子,在 Form 上放置一个 DrawingSurface 控件并处理表单的 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.

形状

这个接口包含一些有用的方法,如果有任何类实现了它们,可用于绘制、命中测试和移动.在这个例子的最后,你可以看到一个 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);
}

线

这是一个实现 IShape 接口的线类.当点击在线测试时,HitTest 返回真.也为了让你更简单的选线,我加了2个hit-testing点:

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

绘图表面

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

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# 中拖动和移动形状的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆