c# winforms graphics gdi+

c# - Dibuje múltiples dibujos a mano alzada de Polilínea o Curva-Agregar función Deshacer



winforms graphics (1)

Estoy tratando de crear una aplicación de dibujo simple con funciones de deshacer y rehacer. Supongo que puede agregar lo que está dibujando en una lista y recurrir a la lista para dibujar todo. Luego, deshacer debería eliminar el último elemento agregado y volver a dibujar todo nuevamente. El problema es, ¿cómo agrego lo que he dibujado en una lista y uso esa lista para deshacer?

Estoy usando el método de redibujo de mapa de bits. Así es como dibujo:

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. }


Necesita almacenar líneas en una List<List<Point>> . Cada elemento de la lista contiene puntos de un dibujo que dibujas usando abajo, mover y arriba. La siguiente línea que dibuje se almacenará en el siguiente elemento de la lista. Cada deshacer, eliminará el último dibujo.

Ponga una instancia de este control en su formulario y manejará el dibujo por usted. También para realizar deshacer, llame a su método 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(); } } }

Nota

  • Con esta lógica, simplemente puede implementar rehacer usando otra List<List<Point>> . Es suficiente copiar el último elemento antes de deshacer para rehacer la lista usando RedoBuffer.Add(Lines.Last()); . Luego, para cada comando de rehacer, es suficiente agregar el último elemento del búfer de rehacer a Lines y eliminarlo del búfer de rehacer. También debe borrar el búfer de rehacer después de cada mouse hacia abajo.
  • Puede usar DrawLines o DrawCurve según sus requisitos. DrawLines dibuja una DrawLines , mientras que DrawCurve dibuja una curva más suave.

  • Prefiero encapsular Lines.Count > 0 en una propiedad como bool CanUndo y hacerla accesible desde fuera de control.

  • Es solo un ejemplo y simplemente puede extender la solución. Por ejemplo, en lugar de List<List<Point>> puede crear una clase Shape contenga List<Point> , LineWidth , LineColor , etc. y realizar la tarea usando List<Shape> .