• Domingo 22 de Diciembre de 2024, 21:14

Autor Tema:  Graficos 2d En C# .net  (Leído 12513 veces)

onetoleo

  • Nuevo Miembro
  • *
  • Mensajes: 11
    • Ver Perfil
Graficos 2d En C# .net
« en: Jueves 10 de Enero de 2008, 16:13 »
0
Hola! mi problema es el siguiente, estoy probando dibujar lineas en c#. Tengo un formulario, en el cual creo un panel. Sobre este panel voy dibujando lineas. La programacion necesaria para hacer esto ya lo tengo realizado. Ademas, tengo tres botones:

un boton de 'borrar' que cuando se hace click realiza un clear() del grafico del panel en cuestion

private void borrar_Click(object sender, EventArgs e)
{
panelDibujo.CreateGraphics().Clear(Color.White);
}

un boton 'guardar' con el cual hago un save() del grafico

private void guardar_Click(object sender, EventArgs e)
{
estadoDelGrafico = panelDibujo.CreateGraphics().Save();
}

y por ultimo un boton 'restaurar', con el cual se supone deberia poder restaurar el grafico del panel

private void restaurar_Click(object sender, EventArgs e)
{
panelDibujo.CreateGraphics().Restore(estadoDelGraf ico);
}

Pero lo que pasa es que yo hago lo siguiente:
1º: hago un par de lineas,
2º: presiono el boton 'guardar'
3º: presiono el boton 'borrar'
4º y ultimo: presiono el boton 'restaurar'

pero las lineas que dibuje que no se vuelven a dibujar. No entiendo porque ya que el uso del metodo Restore() es sencillo. ¿Que es lo que estoy haciendo mal?
Desde ya muchas gracias! Espero su respuesta.

Amilius

  • Miembro HIPER activo
  • ****
  • Mensajes: 665
    • Ver Perfil
Re: Graficos 2d En C# .net
« Respuesta #1 en: Jueves 10 de Enero de 2008, 23:16 »
0
Primero que los controles generalmente se dibujan directamente en pantalla, sin tener memoria propia para almacenar lo que dibujaste en ellos. Ademas lo que estás guardando y restaurando es el "HDC" (Encapsulado en la clase Graphics) y no el "BITMAP" (Encapsulado en la clase Bitmap y es descendiente de la clase Image), es como si guardaras y restauraras el estado de todas las herramientas de dibujo de un pintor, menos el cuadro que estaba pintando.  

Es mejor utilizar un bitmap que almacene lo dibujado. Asi en lugar de "guardar" y "restaurar" tendrías que dibujar el bitmap en el panel y para guardar sólo dibujarias el actual en otro que te sirva para almacenar el estado guardado, o bien guardarlo en disco.

Otra cosa, no tienes que llamar a cada rato a: "CreateGraphics()", sólo una vez y guardar la referencia en un miembro privado. Al cerrar el formulario deberías llamar a Dispose(). Tienes que crear un objeto Graphics para el bitmap y otro para el control donde quieres dibujar, en este caso el panel. Ojo que los objetos Graphics no se crean con new, sino llamando a un método estático de Graphics "Graphics.FromImage(miBitmap)" o en el caso de los controles llamando al método que estas usando "CreateGraphics()".

Quedaria asi:
1. Un Bitmap con el estado actual
2. Otro Bitmap para el estado "guardado"

Siempre dibujas en el bitmap "estado actual"
Borras haciendo clear del bitmap "estado actual"
Dibujas el bitmap actual en el control que desees usando el evento Paint.
Para guardar simplemente dibujas el bitmap actual en el bitmap "guardado".

Una nota más, dependiendo de cómo estén implementados los métodos que dibujan en el bitmap será conveniente usar un bitmap DIB o no. DIB = Device independent bitmap que es un bitmap que se aloja en RAM. Es mejor usar un bitmap DIB si es el procesador central el que dibuja, en cambio si el dibujo lo hace la tarjeta aceleradora es mejor utilizar un bitmap alojado en memoria de tarjeta de video, es decir bitmap dependiende del dispositivo gráfico. Pero en este caso en especial, como no sólo te interesa mostrar un gráfico en pantalla, sino guardar cambios en ese gráfico es mejor que uses un bitmap DIB a 24 bits por pixel para evitar perder información si el usuario cambia de una menor profundidad de color a una mayor.

onetoleo

  • Nuevo Miembro
  • *
  • Mensajes: 11
    • Ver Perfil
Re: Graficos 2d En C# .net
« Respuesta #2 en: Lunes 14 de Enero de 2008, 14:34 »
0
Hola! entiendo lo que me decis, pero no se exactamente cómo hacerlo. Yo tengo el panel donde comienzo a dibujar las lineas, en determinado momento tengo que guardar el estado del dibujo y lo guardo como un mapa de bits. Entonces, cómo obtengo el mapa de bits a partir del objeto panel donde realice los dibujos? Estuve mirando los metodos que me proporcionan los distintos objetos Graphics, BitMaps, Panel pero no veo como los puedo relacionar para obtener un mapa de bits a partir del control, o tampoco hay un metodo que me permita obtener un mapa de bits a partir de un objeto Graphics. Me podrias detallar un poco mas con que metodo puedo hacer lo que vos me planteaste?! Gracias!!!

Amilius

  • Miembro HIPER activo
  • ****
  • Mensajes: 665
    • Ver Perfil
Re: Graficos 2d En C# .net
« Respuesta #3 en: Lunes 14 de Enero de 2008, 19:16 »
0
¿cómo obtengo el mapa de bits a partir del objeto panel donde realice los dibujos?

No puedes por que esos elementos se dibujaron en una zona de memoria que no es propiedad del objeto panel. De hecho el objeto panel carece de la propiedad de un bitmap para dibujar su contenido, es decir que su contenido se dibuja directamente en la pantalla que se presenta al usuario, si mueves una ventana encima de tu panel y luego la quitas de encima verás que borrará lo que dibujaste. Por esa misma razón si quieres aumentar algún gráfico a tu control tienes que dibujarlo respondiendo al evento Paint.

Por eso es que tienes que crear un bitmap que nada tiene que ver con el objeto Panel y en el evento Paint, o cuando sea necesario, dibujar el bitmap en el panel u otro control donde desees dibujarlo.

El objeto Graphics tampoco tiene un bitmap para dibujar. En realidad lo que contiene son instrumentos para dibujar, pero no un bitmap que pueda almacenar lo que dibujaste. Por lo mismo puedes crear un objeto Graphics usando un método estático que te pedira un objeto Bitmap.

Código: Text
  1.  
  2. using System;
  3. using System.Collections.Generic;
  4. using System.ComponentModel;
  5. using System.Data;
  6. using System.Drawing;
  7. using System.Text;
  8. using System.Windows.Forms;
  9. using System.Drawing.Drawing2D;
  10.  
  11. namespace WindowsApplicationTest00
  12. {
  13.     public partial class Form1 : Form
  14.     {
  15.         public Form1()
  16.         {
  17.             InitializeComponent();
  18.             B = new Bitmap(panel1.Width, panel1.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
  19.             G = Graphics.FromImage(B);
  20.             //Como dibujar en el Bitmap de trabajo
  21.             G.SmoothingMode = SmoothingMode.HighQuality;
  22.             G.Clear(Color.White);
  23.             Bs = (Bitmap)(B.Clone());
  24.             Gs = Graphics.FromImage(Bs);
  25.             //Como dibujar en el Bitmap de almacenamiento (HighSpeed por que sólo guardamos resultados)
  26.             Gs.SmoothingMode = SmoothingMode.HighSpeed;
  27.             R = new Random();
  28.         }
  29.  
  30.         private Bitmap B, Bs = null;
  31.         private Graphics G, Gs;
  32.  
  33.         private System.Random R;
  34.  
  35.         private void buttonClear_Click(object sender, EventArgs e)
  36.         {
  37.             G.Clear(Color.White);
  38.             //Indicar al S.O. que el contenido gráfico del panel necesita ser refrescado
  39.             panel1.Invalidate();
  40.         }
  41.  
  42.         private void Form1_FormClosed(object sender, FormClosedEventArgs e)
  43.         {
  44.             Gs.Dispose();
  45.             G.Dispose();
  46.             Bs.Dispose();
  47.             B.Dispose();
  48.         }
  49.  
  50.         private void buttonDraw_Click(object sender, EventArgs e)
  51.         {
  52.             const int MAX = 20;
  53.             for (int i = 0; i <= MAX; i++)
  54.             {
  55.                 G.DrawLine(new Pen(Color.FromArgb(R.Next(256), R.Next(256), R.Next(256))), R.Next(B.Width), R.Next(B.Height), R.Next(B.Width), R.Next(B.Height));
  56.             }
  57.             panel1.Invalidate();
  58.         }
  59.  
  60.         private void buttonSave_Click(object sender, EventArgs e)
  61.         {
  62.             //Para este caso en particular sería mejor un BitBlt usando la opción
  63.             //de copia simple.
  64.             // http://msdn2.microsoft.com/en-us/library/ms532278(VS.85).aspx
  65.             //Es probable que usando DrawImage junto con Gs.SmoothingMode = SmoothingMode.HighSpeed;
  66.             //se obtenga el mismo resultado (copia simple sin efectos ni transformaciones).
  67.             Gs.DrawImage(B, 0, 0);
  68.         }
  69.  
  70.         private void buttonRestore_Click(object sender, EventArgs e)
  71.         {
  72.             G.DrawImage(Bs, 0, 0);
  73.             panel1.Invalidate();
  74.         }
  75.  
  76.         private void panel1_Paint(object sender, PaintEventArgs e)
  77.         {
  78.             e.Graphics.SmoothingMode = SmoothingMode.HighSpeed;
  79.             e.Graphics.DrawImage(B, 0, 0);
  80.         }
  81.  
  82.     }
  83. }
  84.  

onetoleo

  • Nuevo Miembro
  • *
  • Mensajes: 11
    • Ver Perfil
Re: Graficos 2d En C# .net
« Respuesta #4 en: Miércoles 16 de Enero de 2008, 12:53 »
0
Hola! muchas gracias por el ejemplo de codigo. Realmente me sirvio muchisimo, implemente lo que vos me pasaste y realmente funciona :rolleyes: El problema ahora es en algun punto de mi codigo. Tiene un comportamiento medio raro, aca cito una parte donde esta el problema (creo...), espero que si tenes un tiempo (o alguna otra alma caritativa) me puedas dar una mano ;)

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;

namespace Dibujin
{
    class AreaDeDibujo: Control
    {
        private Panel areaDeDibujo;
        private Linea linea;
        private Grafico grafico;
        private Pen lapiz;
        private bool previsualizacion = false;
        private bool esBotonIzquierdo = false;
       
        public AreaDeDibujo(Panel panelDibujo) {
            this.areaDeDibujo = panelDibujo;
            this.grafico = new Grafico (panelDibujo.Size.Width, panelDibujo.Size.Height, panelDibujo);

            //crea una instancia de una linea donde se guardaran las coordenadas
            //de la linea que se va a dibujar
            this.linea = new Linea();

            //subscribe a los eventos del mouse y al que provoca que el
            //control se dibuje en la pantalla.
            this.areaDeDibujo.MouseDown += new MouseEventHandler(comenzarLinea);
            this.areaDeDibujo.MouseMove += new MouseEventHandler(previsualizarLinea);
            this.areaDeDibujo.MouseUp += new MouseEventHandler(finalizarLinea);
            this.areaDeDibujo.Paint += new PaintEventHandler(areaDeDibujo_Paint);
        }

        public void comenzarLinea(Object sender, MouseEventArgs me)
        {
            if (MouseButtons == MouseButtons.Left)
            {
                //se comienza a dibujar la linea solamente cuando se sabe
                //que se trata del boton izquierdo del mouse
                if (this.linea == null)
                    this.linea = new Linea();
                this.esBotonIzquierdo = true;
                this.linea.setComienzo(this.areaDeDibujo.PointToClient (MousePosition));
            }
            else
                this.esBotonIzquierdo = false;
        }

        //este metodo es llamado cada vez que el puntero del mouse
        //se mueva. Con esto se logra que cada vez que se mueva,
        //se dibuja una nueva linea de previsualizacion
        public void previsualizarLinea(Object sender, MouseEventArgs me)
        {
            //con esta llamada se invalida toda la superficie del control
            //areaDeDibujo (que es un panel) y hace que se vuelva a dibujar el mismo
            if (MouseButtons == MouseButtons.Left)
            {
                this.esBotonIzquierdo = true;

                this.previsualizacion = true;
               
                //crea el tipo de lapiz que se utilizara para dibujar
                //la linea de previsualizacion
                this.lapiz = new Pen(Color.DarkSeaGreen, 1);
                lapiz.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
                this.linea.setFinal(this.areaDeDibujo.PointToClient(MousePosition));
                this.areaDeDibujo.Invalidate();
            }
            else
                this.esBotonIzquierdo = false;
        }

        //esta metodo es llamado cuando se produce el evento MouseUp
        //que significa que es boton del mouse ha sido liberado.

        public void finalizarLinea(Object sender, MouseEventArgs me)
        {
                       
            if (this.esBotonIzquierdo == true)
            {
                this.previsualizacion = false;
                lapiz = new Pen(Color.Red, 2);
                this.linea.setFinal(this.areaDeDibujo.PointToClient(MousePosition));
                this.areaDeDibujo.Invalidate();
            }
        }

        void areaDeDibujo_Paint(Object sender, PaintEventArgs e)
        {
            if (this.esBotonIzquierdo == true)
            {
                if (previsualizacion == true)
                {
                    //restaura el estado del grafico antes de volver a dibujar otra linea
                    this.grafico.restaurarEstado();
                    this.grafico.dibujarLinea(this.linea, lapiz);
                }
                else
                {
                        //Como se dibujo una linea definitiva (no es una previsualizacion)
                        //entonces guarda el estado del dibujo.
                        this.grafico.dibujarLinea(this.linea, lapiz);
                        this.grafico.guardarEstadoDelGrafico();
                }
            }
           
            e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed;
            e.Graphics.DrawImage(this.grafico.obtenerMapaDeBits(), 0, 0);
        }  
    }
}

La idea de lo que quiero hacer es que me muestre una linea punteada que me sirva para ver donde quedara mi linea dibujada definitivamente. Mientras mantenga presionado el boton izquierdo del mouse, se dibuja la linea punteada. Cuando se libera el boton izquierdo se dibuja en un color rojo. Pero nunca se pinta de color rojo, excepto, cuando al cursor del mouse, antes de ser liberado, es posicionado sobre el formulario y fuera del panel. Mientras se encuentra dentro del panel el cursor, la linea roja no se dibuja. Alguna idea de lo que puede estar pasando? porque yo observo el codigo y me parece que al menos la logica, esta bien. Sera un tema de algo que pasa en un nivel mas bajo? Muchas gracias.

Saludos!!!  :hola: