繁体   English   中英

绘制多条手绘折线或曲线图-添加撤消特征

[英]Draw multiple freehand Polyline or Curve drawing - Adding Undo Feature

我正在尝试创建具有撤消和重做功能的简单绘图应用程序。 我假设您可以将要绘制的内容添加到列表中并调用该列表以绘制所有内容。 然后,撤消操作应只删除最后添加的项目,然后重新绘制所有内容。 问题是,如何将绘制的内容添加到列表中并使用该列表撤消?

我正在使用位图重绘方法。 这是我的画法:

    Point start, end;
    bool painting;
    private List<PointF> myPoints = new List<PointF>();

    private void pnlMain_MouseDown(object sender, MouseEventArgs e)
    {
        start = e.Location;
        painting = true;
    }

    private void pnlMain_MouseUp(object sender, MouseEventArgs e)
    {
        painting = false;
    }

    private void pnlMain_MouseMove(object sender, MouseEventArgs e)
    {
        if (painting == true)
        {
            end = e.Location;
            g.DrawLine(p, start, end);
            myPoints.Add(e.Location);
            pnlMain.Refresh();
            start = end;
        }
    }

    private void btnUndo_Click(object sender, EventArgs e)
    {
        g.Clear(cldFill.Color);
        if (myPoints.Count > 2)
        {
            myPoints.RemoveAt(myPoints.Count - 1);
            g.DrawCurve(p, myPoints.ToArray());
        }
        pnlMain.Refresh();
        //This works but you have to spam it to get rid of
        //a line and does some weird connections.
    }

您需要将行存储在List<List<Point>> 列表中的每个元素都包含您使用向下,向上移动和向上绘制的图形点。 您绘制的下一行将存储在list的下一个元素中。 每次撤消都会删除最后一个图形。

将此控件的一个实例放在窗体上,它将为您处理图形。 同样要执行撤消,请调用其Undo方法。

using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
public class DrawingSurface : Control
{
    public DrawingSurface() { this.DoubleBuffered = true; }
    List<List<Point>> Lines = new List<List<Point>>();
    bool drawing = false;
    protected override void OnMouseDown(MouseEventArgs e) {
        Lines.Add(new List<Point>());
        Lines.Last().Add(e.Location);
        drawing = true;
        base.OnMouseDown(e);
    }
    protected override void OnMouseMove(MouseEventArgs e) {
        if (drawing) { Lines.Last().Add(e.Location); this.Invalidate(); }
        base.OnMouseMove(e);
    }
    protected override void OnMouseUp(MouseEventArgs e) {
        if (drawing) {
            this.drawing = false;
            Lines.Last().Add(e.Location);
            this.Invalidate();
        }
        base.OnMouseUp(e);
    }
    protected override void OnPaint(PaintEventArgs e) {
        e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
        foreach (var item in Lines)
            e.Graphics.DrawLines(Pens.Black, item.ToArray()); /*or DrawCurve*/
    }
    public void Undo() {
        if (Lines.Count > 0) { this.Lines.RemoveAt(Lines.Count - 1); this.Invalidate(); }
    }
}

注意

  • 使用此逻辑,您可以简单地使用另一个List<List<Point>>实现重做。 使用RedoBuffer.Add(Lines.Last());撤消之前的最后一项复制到重做列表就足够了RedoBuffer.Add(Lines.Last()); 然后,对于每个重做命令,将重做缓冲区的最后一项添加到“ Lines并将其从重做缓冲区中删除就足够了。 每次按下鼠标后,还应清除重做缓冲区。
  • 您可以根据需要使用DrawLinesDrawCurve DrawLines绘制折线,而DrawCurve绘制更平滑的曲线。

  • 我更喜欢将Lines.Count > 0封装在bool CanUndo类的属性中,并使其可以从控件外部进行访问。

  • 这只是一个示例,您可以扩展解决方案。 例如,代替List<List<Point>>您可以创建一个包含List<Point>LineWidthLineColor等的Shape类,并使用List<Shape>执行任务。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM