Animación en java

De ChuWiki

Vamos a hacer un pequeño programa java tonto en el que saldrá una ventana, dentro de ella un línea diagonal cambiará de vértices cada segundo.

Este ejemplo nos servirá para comentar cómo se hace una animación en java.


Algunos conceptos de gráficos en java[editar]

Cuando queramos hacer nuestros propios gráficos, debemos heredar de algún componente java (en este caso he elegido un JPanel) y redefinir el método paint(). En este metodo debemos hacer nuestro dibujo usando el Graphics que nos pasan.

Queremos dibujar una diagonal, así que en el método paint() dibujamos una linea desde el punto x1,y1 al punto x2,y2. Estas son variables que definiremos en la clase, que representan las esquinas y a las que haremos cambiar de valor para que la diagonal se mueva

Conviene en ese componente que usamos para dibujar redefinir también el método getPreferredSize(), para hacer que tenga un tamaño que nosotros queramos. He elegido de dimensiones 100x100 pixels. Así que las variables x1,x2,y1,y2 que mencionamos antes valdrán 0 o 100, para hacer la diagonal que vaya de esquina a esquina.

Para hacer el movimiento, en un hilo independiente del hilo EDT (Event Dispatch Thread) (mas adelante explicamos lo del hilo) debemos cambiar los valores de las coordenadas, llamar al método repaint() del panel para hacer que lo repinte y luego hacer una espera hasta el siguiente cambio. En mi caso he elegido un segundo de espera. Todo esto debería ir en un bucle, para que la diagonal cambie varias veces.

Lo del hilo de EDT: En ningún caso podemos meternos en un bucle indefinido ni hacer esperas como consecuencia de la pulsación de un botón (un actionPerfomed()), ni cualquier otro evento de ventana, teclado o ratón. Cuando java nos llama al provocarse cualquiera de estos eventos, lo hace desde el mismo hilo que repinta la ventanas. Si bloqueamos este hilo con esperas o con bucles infinitos, las ventanas dejarán de repintarse. En el enlace anterior tienes una explicación más detallada.

Si queremos que la animación se inicie al pulsar un botón, deberemos crear un hilo aparte para el bucle.

El código de la animación en java[editar]

Aquí tienes el ejemplo de código en java completo, con comentarios. No es ninguna maravilla, pero se pretende que sea simple para que se entienda mejor el concepto.

En este ejemplo el hilo que se usa para el bucle con la espera es el hilo del main, que no es el de repintado de ventanas de awt que comentamos antes. Por ello no es necesario lanzar un hilo explicitamente.

/*
 * Fichero: PruebaMovimiento.java
 * Autor: Chuidiang
 * Fecha: 13/04/07 20:18
 */
package chuidiang.ejemplos;

import java.awt.Dimension;
import java.awt.Graphics;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;


/**
 * Ejemplo de ventana con unas rayas moviendose.
 *
 * @author Chuidiang
 *
  */
public class PruebaMovimiento extends JPanel
{
	/** Coordenadas x1,y1 y x2,y2 de los extremos de
	 * la raya.
	 */
    public int x1 = 0;
    public int y1 = 0;
    public int x2 = 100;
    public int y2 = 100;

    /**
     * Presenta una ventana con el panel dentro. En la ventana
     * una diagonal cambia de vertices cada segundo.
     * @param args
     */
    public static void main(String[] args)
    {
    	// Creacion y visualizacion de la ventana
        JFrame v = new JFrame();
        PruebaMovimiento panel = new PruebaMovimiento();
        v.getContentPane().add(panel);
        v.pack();
        v.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        v.setVisible(true);

        // Bucle para cambiar las coordenadas de los puntos
        while (true)
        {
            if (panel.y1 == 0)
                panel.y1 = 100;
            else
                panel.y1 = 0;

            if (panel.y2 == 0)
                panel.y2 = 100;
            else
                panel.y2 = 0;

            // Se provoca el repintado del panel.
            // La llamada a repaint() hará que java llame al metodo
            // paint() que hemos redefinido.
            panel.repaint();

            // Retardo de un segundo (1000 milisegundos)
            try
            {
                Thread.sleep(1000);
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
    }

    /**
     * Dibuja la diagonal de x1,y1 a x2,y2
     *
     * @param g 
     */
    public void paint(Graphics g)
    {
        super.paint(g);
        g.drawLine(x1, y1, x2, y2);
    }

    /**
     * Devuelve un tamaño preferido para hacer que la ventana tenga
     * tamaño 100x100 pixels
     *
     * @return dimension de 100x100 pixels.
     */
    public Dimension getPreferredSize()
    {
        return new Dimension(100, 100);
    }
}