lunes, 7 de enero de 2013

Graficos en Java, la técnica DobleBuffering

Increíble casi hace 2 años de la ultima entrada... de hecho probablemente cuando la publique ya serán 2 años... pero bueno... espero perdonen mi lentitud, cada día uno sabe mas cosas... y no las comparte que egoísta "la gente" :P jajaja.

Bueno esta vez explicare algo relativamente sencillo, como utilizar doble buffer en java, se que existen cientos de lugares, donde explican esto, pero a mi parecer lo explican de una forma muy compleja, cuando en realidad es algo muy sencillo y util en la mayoría de los casos.

Antes de pasar al código... deberías tener un conocimiento básico de como utilizar gráficos en java... es decir saber dibujar una figura, una cadena, o una imagen algo asi... el problema que trato de exponer es cuando intentas hacer que  lo que sea que dibujas "se mueva", para hacer que una imagen "se mueva" a través de la pantalla se requiere reemplazar la figura con otra parecida en una ubicación diferente en la pantalla, pero al intentarlo solo sabiendo utilizar el método paint() de la clase Canvas te das cuenta que "parpadea", "flashea".

Ej. supongamos que queremos que un personaje camine, tenemos imágenes de un sprite sheet... programamos y llegamos al punto en el que tenemos una imagen algo asi:


Esto pasa porque la clase Canvas cuenta con un método llamado update, el cual borra completamente la pantalla en ciertas ocasiones, y es el culpable de dicho parpadeo... en realidad si tu metodo paint() borra la imagen anterior, no es necesario que update borre la imagen completa, este detalle se corrige sobreescribiendo update con tu codigo de paint() y haciendo que paint llame a update() asi:

    ...
    @Override
    public void update(Graphics g){
        //el codigo que tenias en paint tal cual
    }
    
    @Override
    public void paint(Graphics g){
        update(g);//se llama al metodo update
    }
    ... 
 
 
Pero aun así obtendríamos una imagen que sigue  parpadeando aparentemente menos, pero continua...esto es porque nosotros mismos borramos la imagen antes de dibujar la siguiente, o al menos eso deberíamos hacer..., por lo tanto en cierto momento la pantalla esta vacía... se utiliza la técnica DobleBuffering la cual consiste en solo dibujar imagenes completas en pantalla, esto es mas fácil de explicar con imagenes, la imagen de abajo muestra como funcionaria el código sin usar DobleBuffering:



Doble buffering consiste realizar los cálculos y dibujar las figuras en memoria antes de mostrarlos al usuario la siguiente imagen muestra de forma mas gráfica doble buffering



Utilizar esta técnica es relativamente sencillo solo debemos agregar dos nuevos atributos en nuestra clase Canvas una imagen y un objeto Graphics, y en el constructor inicializamos estos atributos creando un nuevo objeto BufferedImage y obteniendo su objeto Graphics con el método getGraphics() ahora en nuestro método update en lugar de utilizar el parámetro Graphics utilizaremos el objeto Graphics de nuestra imagen que esta en memoria y al final solo dibujaremos la imagen de la memoria la cual ya fue completamente renderizada, podemos verlo mejor en el siguiente fragmento de código

public class MiCanvas extends Canvas{
    public static final int _WIDTH;
    public static final int _HEIGHT;
    private BufferedImage imagenBuffer;
    private Graphics g_imagenBuffer;
 
    public MiCanvas(){
        this.setSize(_WIDTH, _HEIGHT);
        //creamos la imagen en memoria
        imagenBuffer = new BufferedImage(_WIDTH,
                          _HEIGHT
                          BufferedImage.TYPE_INT_RGB
                      );
        //obtenemos los graficos
        g_imagenBuffer = imagenBuffer.getGraphics();
    }
    
    @Override
    public void update(Graphics g){
       //realizamos nuestros calculos 
       //pero ahora utilizando g_imagenBuffer en lugar de g
       //y por ultimo imprimimos la imagen que tenemos en  memoria
       g.drawImage( imagenBuffer, 0, 0, this );
    }
    ... 

Después de haber realizado los cambios, nuestro personaje caminará mas fluido como se muestra en esta imagen:
Pero no le crean a los las imágenes gif, pueden hacer la prueba ustedes mismos yo igual dejo el código del Megaman donde se puede ver el uso del DobleBuffering lo cual es una técnica sencilla, pero muy útil.

liga para descargar el código fuente del proyecto de NetBeans Megaman:
Proyecto de NetBeans "Megaman"

Si llegaste hasta este párrafo... ¡¡¡Muchas gracias por leer mi blog!!! un entrada cada 2 años... difícil tener fans jajaja ;) hasta la próxima esperemos que sea menos de 2 años.

martes, 11 de enero de 2011

Tablas en netbeans

muchas veces me han preguntado, oye como se usan las tablas en netbeans? o como puedo hacer dinámica una tabla en java?, y la mas frecuente como puedo hacer dinámica una tabla con netbeans? la cual es la misma que la anterior, por lo que decidí escribir cada paso de lo que yo normalmente hago cuando manejo tablas, no se si sea lo mas correcto, pero a mi me funciona:

Aquí supondré que sabemos usar netbeans hasta el punto en el que se inserta una tabla, es decir cuando podemos ver algo como esto:

ya teniendo la tabla creada se pueden modificar sus propiedades de forma gráfica dando click-derecho sobre la tabla que creamos


aparecerá un cuadro de dialogo que describe las propiedades de la tabla, en la primera pestaña "modelo de la tabla" se indica de donde se obtendrán los datos de la tabla, la verdad, de esa pestaña no se casi nada si embargo si nos pasamos a la pestaña que dice Columnas 1

podemos ver las propiedades de cada columna 2 en esta parte podemos cambiar el tipo de el valor que aceptara la tabla, si es editable o si se puede cambiar el tamaño de la celda y por supuesto el nombre de la columna y los números 3,4,5,6 en la selección de modelo indican la forma en que se podrán seleccionar las celdas de la tabla; a continuación una descripción de lo que hacen:
3 solo permite la selección de filas
si se selecciona 4 solo se podrá seleccionar una sola celda
si se selecciona 5 se podrá seleccionar múltiples celdas, pero estas deberán ser vecinas
y por ultimo si se selecciona 6 se podrá seleccionar celdas sin importar que sean vecinas o no
Los tipos que se pueden seleccionar en las tablas son los que se muestran en la imagen, lo cual puede ser útil para recabar datos con formato, en lo personal, no me gusta usar las jtables para recabar datos porque siempre se tiene un problema al insertar el ultimo dato, pero de igual forma al definir el tipo del objeto de una columna esta no aceptara que se inserte otro tipo de valor y en adición, al seleccionar boolean el valor de las columnas cambiaran por  un checkbox donde la palomita significa true, y vació false
Después de cambiarle el formato a la tabla todo lo que quieras, podemos seguir con lo dinámico, ahhh la pestaña de filas o rows solo permite agregar o quitar renglones en la tabla, pero bueno eso no nos sirve si lo que queremos es ponerlos dinamicamente. 
Esto de formatear la tabla servirá ahora tenemos una tabla que solo acepta ciertos tipos de datos, con todos los renglones en blanco.
estas tablas, sin tener que ver con netbeans se manejan de forma diferente de la que muchos pensamos, la jTable es mas bien una versión gráfica, y sus datos provienen de un TableModel y ese es el que se necesita saber utilizar bueno, en si el TableModel no, sino un hijo de este, el DefaultTableModel, el cual permite manipularlo fácilmente. solo necesitamos pues sacarlo de ahí, ya que si revisas el código que genero el netbeans en la función de initComponents dice algo como 

new jtable(new DefaultTableModel{cosas raras de netbeans});

en las cosas raras de netbeans se desarrollan todas las características que seleccionamos gráficamente para aplicar a la tabla, entonces, después de initComponets sacamos el objeto del modelo de la tabla, lo casteamos y lo guardamos en un atributo de nuestra clase.

private javax.swing.table.DefaultTableModel modelo;//atributo de nuestra clase
public Inicio() {//este es el constructor de la tabla
        initComponents();
        modelo = (javax.swing.table.DefaultTableModel)tabla.getModel();//con esta linea obtenemos el modelo
        tabla.setModel(modelo);//con esta instruccion se pueden cambiar las caracteristicas de la tabla por otro modelo
    }
y con el modelo guardado podemos realizar varias acciones como agregar un renglón, borrar un renglón, agregar datos, modificarlos, y obtener los valores de la tabla.

//borrar renglón seleccionado
        try{
            modelo.removeRow(tabla.getSelectedRow());
        }catch(Exception e){
            javax.swing.JOptionPane.showMessageDialog(this, "Seleccione almenos
            una celda","Error",javax.swing.JOptionPane.ERROR_MESSAGE);
        }

//insertar renglón con datos
        modelo.addRow(new Object[]{23,"Hola",23.5,true});//Los datos del nuevo
        renglon de la tabla, se puede insertar un renglon vacio si en lugar de los
        datos se pone {}

//modificar datos de la tabla esto se puede hacer directamente desde la tabla, pero lo haremos con el modelo

        modelo.setValueAt("valorNuevo",renglon,columna);

//tomar un valor de la tabla ojo:los valores salen en forma de object por lo que se necesitan castear
        Object variable = modelo.getValueAt(renglon,columna);

Y listo tenemos una tabla dinámica ;)

de cualquier forma dejo el código de ejemplo en mi pagina http://luismy.espaciogratis.info

bueno, actualice esta entrada, porque me di cuenta de que ya la visitan mas seguido y tenia varios errores de ortografía... bueno cualquier comentario es bienvenido, de todos modos creo que puedo borrar los que no me gusten ;D