Mostrando las entradas con la etiqueta Sprite. Mostrar todas las entradas
Mostrando las entradas con la etiqueta Sprite. Mostrar todas las entradas

viernes, 27 de febrero de 2015

El Demo del Día: Graficar en el ListView de WinForms

Graficar en el ListView de WinForms

En este post veremos como crear graficos dentro de un ListView en Windows Forms, por ejemplo, para listar los empleados con su foto y una imagen con un número de estrellas que muestran su desempeño.

Requerimiento

Se necesita mostrar imágenes en los sub elementos de un elemento de un ListView. Por defecto, este muestra solo textos pero no imagenes.

Solución

- Configurar la Propiedad OwnerDraw en true del ListView
- Programar los eventos DrawColumnHeader, DrawItem y DrawSubItem para dibujar las cabeceras, las filas y pintar los sub elementos (textos e imágenes cargadas de archivos de disco).

Crear una Aplicación Windows Forms en C#

En Visual Studio crear un proyecto Windows Forms en C# con el nombre de "ListView_Grafico", luego cambiar el nombre del formulario a "frmEmpleado".

Crear una carpeta llamada "Imagenes" y agregar 9 archivos jpg con el nombre de 1.jpg, 2jpg, hasta 9.jpg con las fotos de los empleados. También conseguir una imagen "Rating.png" de 334 x 281 conteniendo el rating de desempeño, similar a la siguiente figura:



Nota: Vamos a usar un solo archivo (sprite) para mostrar los desempeños que van del 1 al 4.

Crear la Clase Entidad para el Empleado

Crear la clase "beEmpleado" escribiendo el siguiente código:

namespace ListView_Grafico
{
    public class beEmpleado
    {
        public int IdEmpleado { get; set; }
        public string Nombres { get; set; }
        public int Desempeño { get; set; }
    }
}

Programar el Formulario con el ListView

Regresar al formulario "frmEmpleado" y agregar un ListView llamado "lvwEmpleado" el cual debe estar acoplado a todo el formulario cuyo tamaño es de 600 de ancho x 550 de alto y esta centrado, similar a la siguiente figura:


Escribir el siguiente código en el formulario:

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

namespace ListView_Grafico
{
    public partial class frmEmpleado : Form
    {
        List<beEmpleado> lbeEmpleado;
        Bitmap bmp;
        Rectangle rect;        
        string ruta = @"C:\Data\NET\Practicas\WinForms\ListView_Grafico\Imagenes\";

        public frmEmpleado()
        {
            InitializeComponent();
        }

        private void crearImagenRating()
        {
            string archivo = String.Format("{0}Rating.png",ruta);
            bmp = new Bitmap(archivo);
        }

        private void crearColumnasListView()
        {
            lvwEmpleado.Columns.Add("Id", 50);
            lvwEmpleado.Columns.Add("Nombre del Empleado", 220);
            lvwEmpleado.Columns.Add("Foto", 100);
            lvwEmpleado.Columns.Add("Desempeño", 100);
        }

        private void configurarListView()
        {
            //Configurar el Alto de las Filas
            ImageList imgList = new ImageList ();
            imgList.ImageSize = new Size(1, 50);
            lvwEmpleado.SmallImageList = imgList;
            //Configurar la Apariencia
            lvwEmpleado.View = View.Details;
            lvwEmpleado.FullRowSelect = true;
            lvwEmpleado.HotTracking = true;
            //Configurar el Pintado
            lvwEmpleado.OwnerDraw = true;         
            lvwEmpleado.DrawColumnHeader += 
            new DrawListViewColumnHeaderEventHandler(dibujarCabecera);
            lvwEmpleado.DrawItem += 
            new DrawListViewItemEventHandler(dibujarFila);
            lvwEmpleado.DrawSubItem += 
            new DrawListViewSubItemEventHandler(dibujarCelda);
        }

        private void obtenerEmpleados()
        {
            lbeEmpleado = new List<beEmpleado>();
            lbeEmpleado.Add(new beEmpleado { IdEmpleado = 1, 
            Nombres = "Nadine Heredia", Desempeño = 2 });
            lbeEmpleado.Add(new beEmpleado { IdEmpleado = 2, 
            Nombres = "Ollanta Humala", Desempeño = 2 });
            lbeEmpleado.Add(new beEmpleado { IdEmpleado = 3, 
            Nombres = "Valeria Maza", Desempeño = 4 });
            lbeEmpleado.Add(new beEmpleado { IdEmpleado = 4, 
            Nombres = "Cristina Fernandez", Desempeño = 3 });
            lbeEmpleado.Add(new beEmpleado { IdEmpleado = 5, 
            Nombres = "Alan Garcia", Desempeño = 1 });
            lbeEmpleado.Add(new beEmpleado { IdEmpleado = 6, 
            Nombres = "Alberto Fujimori", Desempeño = 2 });
            lbeEmpleado.Add(new beEmpleado { IdEmpleado = 7, 
            Nombres = "Alejandro Toledo", Desempeño = 3 });
            lbeEmpleado.Add(new beEmpleado { IdEmpleado = 8, 
            Nombres = "Inocencio Perez", Desempeño = 1 });
            lbeEmpleado.Add(new beEmpleado { IdEmpleado = 9, 
            Nombres = "Luis Dueñas", Desempeño = 4 });
        }

        private void llenarListViewEmpleados()
        {
            ListViewItem fila;
            foreach (beEmpleado obeEmpleado in lbeEmpleado)
            {                
                fila = lvwEmpleado.Items.Add(obeEmpleado.IdEmpleado.ToString());
                fila.SubItems.Add(obeEmpleado.Nombres);
                fila.SubItems.Add(obeEmpleado.IdEmpleado.ToString());
                fila.SubItems.Add(obeEmpleado.Desempeño.ToString());
            }
        }

        private void crearListView(object sender, EventArgs e)
        {
            crearImagenRating();
            crearColumnasListView();
            configurarListView();
            obtenerEmpleados();
            llenarListViewEmpleados();            
        }

        private void dibujarCabecera(object sender, DrawListViewColumnHeaderEventArgs e)
        {
            e.Graphics.FillRectangle(Brushes.Black, e.Bounds);
            StringFormat sf= new StringFormat();
            sf.Alignment=StringAlignment.Center;
            sf.LineAlignment = StringAlignment.Center;
            e.Graphics.DrawString(e.Header.Text, new Font("Arial", 10, FontStyle.Bold),
            Brushes.White, e.Bounds, sf);
        }

        private void dibujarFila(object sender, DrawListViewItemEventArgs e)
        {
            rect = new Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width, 50);
            if ((e.State & ListViewItemStates.Selected) != 0)
            {
                e.Graphics.FillRectangle(Brushes.Black, rect);
                e.DrawFocusRectangle();
            }
        }

        private void dibujarCelda(object sender, DrawListViewSubItemEventArgs e)
        {
            if (e.ColumnIndex > -1)
            {
                rect = new Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width-20, 50);
                if (e.ColumnIndex < 2)
                {
                    Font fuente = new Font("Arial", 8);
                    Brush brocha = Brushes.Black;
                    StringFormat sf = new StringFormat();
                    sf.LineAlignment = StringAlignment.Center;
                    bool seleccionado = (e.ItemState & ListViewItemStates.Selected) != 0;
                    if (seleccionado)
                    {
                        brocha = Brushes.White;
                        fuente = new Font("Arial", 10, FontStyle.Bold);
                    }
                    e.Graphics.DrawString(e.SubItem.Text, fuente, brocha, rect,sf);
                    return;
                }
                else
                {
                    if (e.ColumnIndex == 2)
                    {
                        using (MemoryStream ms = new MemoryStream(obtenerFoto(e.SubItem.Text)))
                        {
                            Image img = Image.FromStream(ms);
                            e.Graphics.DrawImage(img, rect);
                        }
                    }
                    else
                    {
                        int n=int.Parse(e.SubItem.Text);
                        int h = 281/4;
                        int y=h*(n-1);
                        rect = new Rectangle(0, y, 334, h);
                        Image img = bmp.Clone(rect, bmp.PixelFormat);
                        e.Graphics.DrawImage(img, e.Bounds.X, e.Bounds.Y, 100, 40);
                    }
                }
            }
        }

        private byte[] obtenerFoto(string idEmpleado)
        {            
            string archivo = String.Format("{0}{1}.jpg", ruta, idEmpleado);
            byte[] foto = File.ReadAllBytes(archivo);
            return foto;
        }
    }
}

Nota: La función principal es "crearListView" y esta asociada al evento "Load" del formulario, la cual llama a casi todos los métodos usados.

Una de los problemas que se presento al momento de desarrollar fue aumentar el alto de cada fila, lo cual se logra asociando un ImageList a la propiedad SmallImageList del ListView, para lo cual se le da un tamaño al ImageList mediante su propiedad "ImageSize", por ejemplo, le damos el alto de 50.

Probar la Aplicación Windows Forms

Grabar la aplicación y ejecutarla con F5. Se mostrará la siguiente ventana:


Observar que la cabecera del ListView tiene fondo negro, texto de color blanco en negrita y centrado horizontal y alineado vertical al centro.

Los elementos del ListView cuando no están seleccionados tienen fondo blanco, texto de color negro y están alineados verticalmente al centro.

Al pasar el mouse por cada elemento este se selecciona (propiedad HotTracking=true) y el fondo es negro y el color del texto es blanco en negrita y con fuente mas grande.

En la tercera columna se muestran las fotos obtenidas de los archivos de acuerdo al código del empleado y finalmente, en la última columna se presenta una sección del archivo de Rating, el cual se dividió lógicamente en 5 filas y de acuerdo al desempeño se obtiene solo una fila.

Comentario Final

En este breve post he compartido como crear gráficos dentro de un ListView para mejorar su apariencia, hay controles de terceros muy buenos como el ObjectListView que permiten mostrar todo tipo de imágenes, y lo que quería era demostrar que también podemos hacer lo mismo configurando la propiedad OwnerDraw y programando en los eventos DrawColumnHeader, DrawItem y DrawSubItem.

Descarga

martes, 17 de junio de 2014

El Demo del Día: Animación usando Sprites en Windows Forms

Animación usando Sprites en Windows Forms

El Demo de hoy es una animación en Windows Forms usando un sprite o archivo con una secuencia de imagenes. Los sprites permiten reducir el numero de accesos a archivos para una aplicación que trabaja con imagenes, sobre todo es muy usado en los juegos.

Paso 1: Archivo con el Sprite a Animar

En este ejemplo tenemos un archivo llamado "Caminante.jpg" que tiene 3 filas x 6 columnas, es decir 18 cuadros, pero en este caso solo hay 14 imágenes diferentes. La primera fila tiene 6 imágenes con posiciones hacia la derecha y la segunda fila tiene 6 imágenes con posiciones hacia la izquierda.
El archivo tiene una dimensión de 624 x 450 pixeles por lo que cada imagen seria de 104 de ancho por 150 de alto.



Paso 2: Diseño del Formulario Windows Forms en .NET

Debemos crear una Aplicación en C# para Windows Forms llamada: "Animacion_Sprite" y renombrar el formulario a "frmCaminante".
Primero agregar un control PictureBox llamado "picCaminante" de tamaño "50x50", luego 2 controles RadioButton: "rbDerecha" y "rbIzquierda".
Finalmente, agregar un Timer llamado: "tmrAnima" con la propiedad Enable en "true" y el Interval en "100" milisegundos, tal como se muestra en la figura:



Paso 3: Código del Formulario en C# .NET

Escribir el siguiente código en el formulario, la función cargarImagen esta asociada al evento "load" del formulario y la función "animarCaminante" esta asociado al evento "Tick" del Timer. Además la función "caminarDerecha" esta asociada al radio button "rbDerecha" y la función: "caminarIzquierda" esta asociada al radio button "rbIzquierda".

    public partial class frmCaminante : Form
    {
        Bitmap bmp;
        Rectangle rect;
        int posX,posY,x,c;

        public frmCaminante()
        {
            InitializeComponent();
        }

        private void cargarImagen(object sender, EventArgs e)
        {
            bmp = new Bitmap("Caminante.png");          
        }

        private void animarCaminante(object sender, EventArgs e)
        {
            rect = new Rectangle(posX, posY, 104, 150);
            picCaminante.Image = bmp.Clone(rect, bmp.PixelFormat);
            if (rbDerecha.Checked) animarDerecha();
            if (rbIzquierda.Checked) animarIzquierda();
        }

        private void animarDerecha()
        {
            posX += 104;
            c++;
            picCaminante.Left = x;
            if (x <= this.Width) { x += 10; }
            else { x = -picCaminante.Width; }
            if (c == 5)
            {
                c = 0;
                posX = 104;
            }
        }

        private void animarIzquierda()
        {
            posX += 104;
            c++;
            picCaminante.Left = x;
            if (x>-picCaminante.Width) { x -= 10; }
            else { x = this.Width; }
            if (c == 5)
            {
                c = 0;
                posX = 104;
            }
        }

        private void caminarDerecha(object sender, EventArgs e)
        {
            if (rbDerecha.Checked)
            {
                c = 0;
                posX = 104;
                posY = 0;
            }
        }

        private void caminarIzquierda(object sender, EventArgs e)
        {
            if (rbIzquierda.Checked)
            {
                c = 0;
                posX = 104;
                posY = 150;
            }
        }
    }

Paso 4: Ejecución del Formulario Windows Forms

Después de escribir el código de arriba, crear el archivo: "Caminante.jpg" en la carpeta bin/Debug de la aplicación y ejecutar pulsando F5. Por defecto la animación se inicia a la derecha, para cambiar seleccionar el radio button.


Descarga:
Demo04_Animacion_Sprite