绘制多个手绘折线或曲线图 - 添加撤消功能 [英] Draw multiple freehand Polyline or Curve drawing - Adding Undo Feature

查看:21
本文介绍了绘制多个手绘折线或曲线图 - 添加撤消功能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to create a simple drawing application with undo and redo features. I assume you can add what you are drawing into a list and calling upon the list to draw everything. Then undoing should just remove the last added item and redraw everything again. The problem is, how do I add what I've drawn into a list and use that list to undo?

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

I'm using the bitmap redraw method. This is how I draw:

    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> 中存储行.列表的每个元素都包含您使用向下、移动和向上绘制的绘图点.您绘制的下一行将存储在列表的下一个元素中.每次撤消,都会删除最后一张图.

You need to store lines in a List<List<Point>>. Each element of the list contains points of a drawing which you draw using a down, move and up. The next line which you draw, will store in the next element of list. Each undo, will remove the last drawing.

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

Put an instance of this control on your form and it will handle the drawing for you. Also to perform undo, call its Undo method.

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> 实现重做.使用 RedoBuffer.Add(Lines.Last()); 将撤销前的最后一项复制到重做列表就足够了.然后对于每个重做命令,将重做缓冲区的最后一项添加到Lines 并从重做缓冲区中删除就足够了.您还应该在每次按下鼠标后清除重做缓冲区.
  • 您可以根据需要使用 DrawLinesDrawCurve 之一.DrawLines 绘制多段线,而 DrawCurve 绘制更平滑的曲线.

  • Using this logic, you can simply implement redo using an other List<List<Point>>. It's enough to copy the last item before undo to redo list using RedoBuffer.Add(Lines.Last());. Then for each redo command, it's enough to add the last item of redo buffer to Lines and remove it from redo buffer. You should also clear the redo buffer after each mouse down.
  • You can use either of DrawLines or DrawCurve based on your requirement. DrawLines draws a poly-line, while DrawCurve draws a more smooth curve.

我更喜欢封装 Lines.Count >0 在像 bool CanUndo 这样的属性中,并使其可从控制之外访问.

I prefer to encapsulate Lines.Count > 0 in a property like bool CanUndo and make it accessible from outside of control.

这只是一个示例,您可以简单地扩展解决方案.例如,您可以创建一个包含 ListLineWidth 的 Shape 类,而不是 List>LineColor 等,并使用 List 执行任务.

It's just an example and you can simply extend the solution. For example, instead of List<List<Point>> you can create a Shape class containing List<Point>, LineWidth, LineColor, etc and perform task using List<Shape>.

这篇关于绘制多个手绘折线或曲线图 - 添加撤消功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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