c# - copiando dibujo a mano libre del panel en visual studio 2013
winforms picturebox (1)
Quiero dibujar a mano libre en un formulario (cuadro de imagen) en Visual Studio y copiar la misma figura (que dibujo) en otro panel / cuadro de imagen. Además, no deben ser puntos que formen una línea, sino una línea continua. Por favor ayuda.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
Pen p_white;
bool draw = true;
private Graphics objgraphics;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
Pen p_black = new Pen(new SolidBrush(Color.Black));
if (draw)
{
objgraphics = panel1.CreateGraphics();
}
}
/*private void panel1_MouseDown(object sender, MouseEventArgs e)
{
bool draw = true;
}*/
private void panel1_MouseMove_1(object sender, MouseEventArgs e)
{
Rectangle rEllipse = new Rectangle();
switch (e.Button)
{
case MouseButtons.Left:
rEllipse.X = e.X;
rEllipse.Y = e.Y;
rEllipse.Width = 5;
rEllipse.Height = 5;
objgraphics.DrawEllipse(System.Drawing.Pens.Black, rEllipse);
break;
case MouseButtons.Right:
rEllipse.X = e.X;
rEllipse.Y = e.Y;
rEllipse.Width = 3;
rEllipse.Height = 3;
objgraphics.DrawEllipse(System.Drawing.Pens.Black, rEllipse);
break;
default:
return;
}
}
/*private void panel1_MouseUp(object sender, MouseEventArgs e)
{
bool draw = false;
} */
private void form_Paint(object sender, EventArgs e)
{
}
private void panel2_Paint(object sender, PaintEventArgs e)
{
Pen p_black = new Pen(new SolidBrush(Color.Black));
if (draw)
{ objgraphics = panel1.CreateGraphics();
}
}
private void button2_Click(object sender, EventArgs e)
{
this.Close();
}
}
}
Al mirar su código, me temo que tengo que decir: Todo esto está mal .
Lamento ser tan directo, pero nunca debes usar el control.CreateGraphics !!
-
Lo primero que debe hacer es tirar el objeto
Graphics objgraphics
.
¡Es (casi) siempre incorrecto almacenar un objeto
Graphics
!
En su lugar, debe usar el que obtiene del parámetro
e.Graphics
en los eventos
Paint
de sus controles.
Tenga en cuenta que los
Graphics
no contienen
ningún gráfico, es una herramienta utilizada para dibujar en un
Bitmap
asociado o la superficie de un control.
- Lo siguiente que debe hacer es comprender cómo dibujar líneas a mano alzada. A menudo uno puede ver el código que tiene; pero es inútil y solo es un ejemplo de cuántas estupideces encuentras en las presentaciones. Olvídalo. Siempre se verá como una mierda, ya que los círculos simplemente nunca se verán suaves y, tan pronto como mueva el mouse más rápido, las pseudo líneas se desmoronarán por completo.
Hay un buen método
DrawCurve
que dibujará líneas suaves.
Lo alimentas con un
Pen
y una serie de
Points
.
Esto es lo que usaremos.
Volvamos a lo básico: ¿Cómo crear un gráfico?
Ahora sabemos que debe llamar a
DrawCurve
en el evento
Paint
:
e.Graphics.DrawCurve(somePen, somePointsArray);
Esto trae las siguientes preguntas:
- que hay de pluma
- ¿Qué es somePointsArray?
Hay una tercera pregunta oculta:
- ¿Qué hay de dibujar más líneas?
El primero es simple;
crea un
Pen
con un ancho de trazo de 5.5 píxeles como
Pen somePen = new Pen(Color.Blue, 5.5f);
Si lo desea, también puede darle un estilo de línea (guiones).
Ahora para la matriz: en su forma más simple, esto también es fácil.
En el evento
MouseMove
, almacena la
Location
actual en una lista de puntos.
primero lo declaramos a nivel de clase:
List<Point> currentLine = new List<Point>();
Luego comenzamos a llenarlo siempre que se presione el botón izquierdo:
private void panel1_MouseMove_1(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
currentLine.Add(e.Location);
panel1.Invalidate();
}
}
Tenga en cuenta la última línea: llamar a
Invalidate
en un control activa el
sistema
para invocar el evento
Paint
.
Puede parecer complicado, pero esta es la única forma correcta, ya que garantiza que el mismo dibujo también sucederá cuando alguna
otra
razón lo haga necesario.
Necesitamos dibujar porque tenemos cambios en los datos que se deben dibujar.
Pero hay muchas razones
externas
, más notoriamente la secuencia
Minimize/maximize
que borrará el dibujo y también desencadenará el evento
Paint
.
¡Entonces debemos
cooperar
con la forma en que
Windows
dibuja sus controles!
Solo así los gráficos
persistirán
.
También tenga en cuenta que no usamos una matriz, ya que no sabemos cuántos
Points
necesitaremos.
En su lugar, usamos una
List
y luego la enviamos a
Array
.
Vamos a codificar el evento
Paint
para nuestro caso simple:
private void panel1_Paint(object sender, PaintEventArgs e)
{
using (Pen somePen = new Pen(Color.Blue, 5.5f) )
if (currentLine.Count > 1) e.Graphics.DrawCurve(yourPen , currentLine.ToArray());
}
Tenga en cuenta que he creado el
Pen
en una cláusula de
using
.
Esta es una forma económica y segura de garantizar que el
Pen
se deseche correctamente.
¡Observe también cómo lanzamos la
List
a una
Array
!
El código anterior solo funcionaría y le permitiría dibujar una línea a mano alzada.
¿Pero qué pasa con la siguiente línea? ¡No debería conectarse al primero, así que no podemos simplemente agregar más puntos!
Por lo tanto, no solo necesitamos una lista de puntos, sino más que eso, de hecho se requiere una lista de puntos:
List<List<Point>> curves = new List<List<Point>>();
Y le agregamos la curva actual cada vez que se suelta el mouse:
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
if (currentLine.Count > 1) curves.Add(currentLine.ToList()); // copy!!
currentLine.Clear();
panel1.Invalidate();
}
Observe cómo uso un reparto de
List
a
List
para imponer una copia o, de lo contrario, solo se asignaría la referencia y luego, en la siguiente línea, se borrará.
Nuevamente, activamos el evento
Paint
como lo último que se debe hacer.
Ahora deberíamos cambiar el evento
Paint
para mostrar todas las líneas, tanto la que se está dibujando actualmente como todas las anteriores.
private void panel1_Paint(object sender, PaintEventArgs e)
{
using (Pen somePen = new Pen(Color.Blue, 5.5f) )
{
if (currentLine.Count > 1) e.Graphics.DrawCurve(somePen, currentLine.ToArray());
foreach (List<Point> lp in curves)
if (lp.Count > 1) e.Graphics.DrawCurve(somePen, lp.ToArray());
}
}
Ahora básicamente hemos terminado con la parte de dibujo a mano alzada.
Entonces volvemos a su pregunta original: ¿Cómo puede copiar el dibujo a un
segundo
Panel
?
Bueno, ha almacenado todo en la estructura de datos de
curves
.
Entonces tiene dos opciones: simplemente use los mismos datos en el evento
panel2_Paint
o si necesita copiar y cambiar los datos, tal vez adaptarlo a un tamaño diferente.
SO no es un servicio de escritura de código. Por lo general, no debería darle más pistas de lo que escribí en los comentarios anteriores. Pero como esta pregunta surge con tanta frecuencia, escribí el código completo para una aplicación de doodle muy básica.
Aquí hay cosas que aún faltan:
-
Guardar los datos, guardar el dibujo (
Serialize
,DrawToBitMap
) -
Dibujar con diferentes plumas y colores (cree una clase
drawAction
para almacenar todo lo que necesita) -
Usar otras herramientas como Línea o Rectángulo (crear una clase
drawAction
) - Borrar el dibujo (ver abajo)
-
Deshacer y rehacer (mirar en
Stacks
yQueues
) -
Almacenamiento en caché cuando hay una gran cantidad de líneas (dibuje la primera parte en un
BackgroundImage Bitmap
)
Aquí hay un código de limpieza:
curves.Clear(); currentLine .Clear(); panel1.Invalidate();
Noté que su código original le permite dibujar con dos anchos de trazo diferentes usando el botón izquierdo y derecho. Esto solo muestra que este código no es muy bueno. ¿Quién a) pensaría en eso yb) estaría satisfecho con solo dos anchos de trazo ...
Lea esta publicación donde explico un poco sobre cómo crear una clase que pueda almacenar un ancho de lápiz, un color, etc. para que pueda cambiar luego entre las líneas que dibuja.