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 usandoRedoBuffer.Add(Lines.Last());
. Luego, para cada comando de rehacer, es suficiente agregar el último elemento del búfer de rehacer aLines
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
oDrawCurve
según sus requisitos.DrawLines
dibuja unaDrawLines
, mientras queDrawCurve
dibuja una curva más suave. -
Prefiero encapsular
Lines.Count > 0
en una propiedad comobool 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 claseShape
contengaList<Point>
,LineWidth
,LineColor
, etc. y realizar la tarea usandoList<Shape>
.