Sesión 14

 

1. En este ejercicio vamos a practicar con el modo a pantalla completa de Java, para ver que no resulta tan complicado como pueda parecer el trabajar con él.

  1. Antes de comenzar, lee los subapartados 3.4.4 (API de Java 2D), y 3.4.5 (Modo a pantalla completa) del tema 3 de teoría.
  2. Echa un vistazo a la clase Ej2.java que se proporciona en la plantilla de la sesión. Verás que es una versión reducida del ejemplo de animación hecho en la sesión anterior, donde sólo se muestra el Canvas, y dentro el rectángulo y círculo moviéndose. 
  3. Lo primero que vamos a hacer es pasar este JFrame a pantalla completa. Para ello es imprescindible elegir el modo gráfico que queremos (el DisplayMode). En la plantilla se os proporciona también un fichero llamado DlgModos.java. Echadle un vistazo, y veréis que es un tipo de cuadro de diálogo (JDialog). En él se obtienen los modos de pantalla compatibles con vuestro monitor, y se muestran en una JList, para que elijamos uno. Una vez elegido, pulsando el botón de Aceptar se cierra el cuadro de diálogo, quedándose el modo seleccionado en el campo modoSeleccionado.

    Vamos a incorporar este cuadro de diálogo a nuestro JFrame, para que se muestre antes de mostrar la ventana principal, y así elegir el modo gráfico que queramos. Añadimos al final del constructor lo siguiente:
    public Ej2()
    {
    	...
    	// Tomamos el dispositivo grafico
    	GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    	GraphicsDevice gd = ge.getDefaultScreenDevice();
    		
    	// Mostramos dialogo para elegir un modo grafico
    	DlgModos dlg = new DlgModos(gd, this);
    	dlg.show();
    
    	// Activamos el modo a pantalla completa, con el modo grafico seleccionado
    	gd.setFullScreenWindow(this);
    	gd.setDisplayMode(dlg.modoSeleccionado);
    }

    Compilad y ejecutad el programa. Es IMPORTANTE elegir un modo gráfico compatible con nuestra pantalla, pues realmente todos los que muestra no lo son. Para evitar pantallazos y cambios de configuración, podéis elegir el mismo modo que tenéis activo para Windows (normalmente, unos 1024 x 768 con 16 o 32 bits de profundidad de color). Si os fuese demasiado lento, podéis elegir uno de menor resolución (320 x 240, por ejemplo), aunque procurad mantener la misma profundidad de color que tengáis. En general, es cuestión de ir probando hasta que alguno se vea.

    Veréis que el frame pasa a pantalla completa (aunque todavía se verá la barra superior de la ventana, eso lo solucionaremos luego).

  4. Observad que, si elegís una resolución mayor que 320 x 240, el gráfico no ocupa toda la pantalla, sino la parte proporcional a esas dimensiones. Ello se debe a que estamos dibujando una imagen de 320 x 240 dentro de una ventana de resolución mayor. Lo que tenemos que hacer es escalar esa imagen a dibujar, para que ocupe toda la extensión del modo gráfico seleccionado.
    1. Primero declaramos dos variables globales que indicarán el ancho y alto del modo gráfico seleccionado:
      public class Ej2 extends JFrame implements Runnable
      {
      	public static final int ANCHO = 320;
      	public static final int ALTO = 240;
      	MiCanvas mc = new MiCanvas();
      	Thread t = new Thread(this);
      	int yObj = 0;
      	int anchoPantalla;
      	int altoPantalla;
      
    2. Después, una vez elegido el modo de pantalla, asignamos la anchura y altura elegidas a dichas variables. Para ello, cuando se cierre el diálogo del modo gráfico, ponemos:
      public Ej2()
      {
      	...
      	DlgModos dlg = new DlgModos(gd, this);
      	dlg.show();
      	anchoPantalla = dlg.modoSeleccionado.getWidth();
      	altoPantalla = dlg.modoSeleccionado.getHeight();
      
      	...
      }
    3. Finalmente, en el método paint de MiCanvas, hacemos que el backbuffer se dibuje escalado a las dimensiones de la pantalla, y no a ANCHO x ALTO como estaba antes:
      public void paint(Graphics g)
      {
      	if(backbuffer == null)
      		backbuffer = createImage(ANCHO, ALTO);
      	
      	// Dibujamos los gráficos en el backbuffer
      	
      	Graphics off_g = backbuffer.getGraphics();
      	off_g.clearRect(0, 0, ANCHO, ALTO);
      	...
      
      	// Volcamos el backbuffer a pantalla, segun el tamaño de la misma
      
      	g.drawImage(backbuffer, 0, 0, anchoPantalla, altoPantalla, this);
      	g.dispose();
      
      }

      Observad cómo la imagen del backbuffer siempre será de 320 x 240, tal y como la definimos en createImage. Esto nos permite dibujar independientemente de la resolución final, y luego nosotros escalaremos el resultado según la resolución que tengamos elegida.

  5. La barra superior no la hemos quitado aún porque si no no habría forma de cerrar la ventana. Ahora lo que vamos a hacer es quitarla, y sustituir la animación automática por eventos de teclado, de forma que podamos nosotros mover las figuras (arriba y abajo, por ejemplo), desde las flechas del teclado

    Para quitar la barra, colocamos en el constructor (al principio, por ejemplo), el siguiente método:
    public Ej2()
    {
    	this.setUndecorated(true);
    	...
    }

    que hace que la ventana no tenga decoración, y con eso se quita la barra.

    Después, añadimos en ese mismo constructor un evento de teclado (KeyListener) que recogerá las siguientes pulsaciones de teclas:

    Añadimos un evento con todo lo anterior:

    public Ej2()
    {
    	...
    	addKeyListener(new KeyAdapter()
    	{
    		public void keyPressed(KeyEvent e)
    		{
    			if (e.getKeyCode()==KeyEvent.VK_ESCAPE)
    			{
    				System.exit(0);
    			} else if (e.getKeyCode()==KeyEvent.VK_UP) {
    				if (yObj > 0)
    					yObj--;
    			} else if (e.getKeyCode()==KeyEvent.VK_DOWN) {
    				if (yObj < ALTO)
    					yObj++;
    			}
    		}
    	});	
    }

    ¿Qué método utilizamos en el código para saber qué tecla se ha pulsado? ¿Con qué lo comparamos en cada caso para saber si se ha pulsado la tecla indicada?

    Como ahora las figuras las movemos por teclado, quitamos la línea que aumenta la coordenada Y automáticamente en el método run, y hacemos que el bucle sea infinito:

    public void run()
    {	
    	while (true)
    	{
    		// Quitamos esta linea: yObj++;
    		mc.repaint();
    		try
    		{
    			Thread.currentThread().sleep(100);
    		} catch (Exception ex) {}
    	}
    }
  6. Compilad y ejecutad la aplicación, para comprobar que funciona correctamente. Probad los eventos del teclado para mover las figuras.
  7. Por último, vamos a quitar las figuras que dibujábamos, y en su lugar vamos a colocar una imagen ya predefinida, que podamos mover con teclado. Tenéis una llamada figura.png en la plantilla.
    1. En primer lugar, definimos una variable global que guardará la imagen:
      public class Ej2 extends JFrame implements Runnable
      {
      	public static final int ANCHO = 320;
      	public static final int ALTO = 240;
      	MiCanvas mc = new MiCanvas();
      	Thread t = new Thread(this);
      	int yObj = 0;
      	int anchoPantalla;
      	int altoPantalla;
      	Image figura;
    2. Después, en el constructor, obtenemos la imagen, utilizando la clase Toolkit y luego su método createImage:
      public Ej2()
      {
      	...
      	Toolkit tk = Toolkit.getDefaultToolkit();
      	figura = tk.createImage("figura.png");
      	...
      }
    3. Finalmente, en el método paint de MiCanvas, quitamos los dibujos de las figuras, y simplemente dibujamos esta imagen:
      public void paint(Graphics g)
      {
      	if(backbuffer == null)
      		backbuffer = createImage(ANCHO, ALTO);
      	
      	// Dibujamos los gráficos en el backbuffer
      	
      	Graphics off_g = backbuffer.getGraphics();
      	off_g.clearRect(0, 0, ANCHO, ALTO);
      	off_g.drawImage(figura, 0, yObj, 
                              figura.getWidth(this), figura.getHeight(this), this);
      
      	// Quitamos estas lineas, ya no las necesitamos:
      	// off_g.setColor(Color.blue);
      	// off_g.fillRect(5, yObj, 100, 25);
      	// off_g.setColor(Color.green);
      	// off_g.fillOval(125, yObj, 100, 50);
      
      	// Volcamos el backbuffer a pantalla, segun el tamaño de la misma
      
      	g.drawImage(backbuffer, 0, 0, anchoPantalla, altoPantalla, this);
      	g.dispose();
      
      }

      Vemos que dibujamos la figura en la coordenada X = 0, y variaremos su Y desde las flechas del teclado, como antes.

  8. Compila y ejecuta ahora la aplicación. Comprueba que la figura se carga bien, y la puedes mover desde el teclado.
  9. (OPTATIVO) Esta parte hazla únicamente si tienes tiempo y quieres, no es necesario entregarla:

PARA ENTREGAR