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 aLinesy eliminarlo del búfer de rehacer. También debe borrar el búfer de rehacer después de cada mouse hacia abajo. -
Puede usar
DrawLinesoDrawCurvesegún sus requisitos.DrawLinesdibuja unaDrawLines, mientras queDrawCurvedibuja una curva más suave. -
Prefiero encapsular
Lines.Count > 0en una propiedad comobool CanUndoy 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 claseShapecontengaList<Point>,LineWidth,LineColor, etc. y realizar la tarea usandoList<Shape>.