绘制多个手绘折线或曲线图 – 添加撤消function

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

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

Point start, end; bool painting; private List myPoints = new List(); 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>存储行。 列表的每个元素都包含使用向下,向上和向上绘制的绘图点。 您绘制的下一行将存储在列表的下一个元素中。 每次撤消,都会删除最后一张图。

将此控件的实例放在表单上,​​它将为您处理绘图。 同样要执行撤消,请调用其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> Lines = new List>(); bool drawing = false; protected override void OnMouseDown(MouseEventArgs e) { Lines.Add(new List()); 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());撤消之前的最后一项复制到重做列表就足够了RedoBuffer.Add(Lines.Last()); 。 然后对于每个重做命令,足以将最后一个重做缓冲区项添加到Lines并从重做缓冲区中删除它。 每次按下鼠标后,还应清除重做缓冲区。
  • 您可以根据您的要求使用DrawLinesDrawCurveDrawLines绘制折线,而DrawCurve绘制更平滑的曲线。

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

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