c# winforms panel picturebox

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 y Queues )
  • 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.