viernes, 27 de mayo de 2011

Interacción avanzada con aplicaciones Java utilizando el teclado


En muchas aplicaciones Java queremos interaccionar con el teclado no únicamente para introducir datos, sino para hacer otro tipo de acciones. Un ejemplo de esto son los juegos, en los que queremos detectar qué teclas o combinaciones de teclas se están pulsando en cada momento.

Java proporciona la interfaz KeyListener que deben implementar todas aquellas clases interesadas en procesar eventos del teclado.

La interfaz define tres métodos:
  • void keyPressed(KeyEvent e) para cuando una tecla se pulsa
  • void keyReleased(KeyEvent e) para cuando una tecla se suelta
  • void keyTyped(KeyEvent e) para cuando se escribe un caracter

Una forma de implementar la interfaz KeyListener para conocer qué teclas se están pulsando en un momento determinado en una aplicación Java es la siguiente:

1. Creamos una clase que implemente la interfaz KeyListener

2. Creamos los atributos de la clase
Nos interesará crear:
  • Un array que almacene el estado de cada una de las teclas de un teclado; este estado puede ser un booleano (pulsado o no pulsado). Un valor que se puede utilizar como tamaño del array y que valdrá para la mayoría de teclados es 256.  
  • También podríamos querer tener otro array donde almacenemos estados más allá de un simple booleano (por ejemplo un enumerado con pulsado, pulsado por primera vez o pulsado y mantenido pulsado).
  • Otros atributos que pueden interesarnos son booleanos que nos indiquen si se ha pulsado una tecla o no, para los casos en los que nos de igual qué tecla se haya pulsado.
3. Implementamos los métodos de la interfaz
Como hemos visto antes, los métodos reciben como parámetro un KeyEvent, el cual tiene un método getKeyCode que nos devuelve el código de la tecla. Una vez comprobemos que este código está dentro de los valores admitidos por nuestro array (entre 0 y 255) actualizamos los atributos para almacenar el estado actual del teclado.

4. Implementamos los métodos para preguntar por el estado de las teclas
Finalmente, implementaremos los métodos que queramos para preguntar a nuestra clase acerca del estado actual del teclado. Por ejemplo:

  • boolean teclaPulsada(int tecla)
  • boolean teclaNoPulsada(int tecla)
  • boolean algunaTeclaPulsada()
  • boolean algunaTeclaNoPulsada()

Una vez tengamos nuestra clase implementada (y probada) ya podemos utilizarla en nuestra aplicación.
Primero nos definimos e inicializamos un objeto de dicha clase y después le iremos preguntando por las teclas acerca de las que nos interesa conocer su estado.

Referencias:

  • Esta entrada ha sido inspirada por esta y esta, en ellas podéis encontrar ejemplos de lo que he explicado.
  • Aquí podéis encontrar más información de cómo implementar la interfaz KeyListener.
  • Una librería que tiene buena pinta para manejar entrada de datos en juegos es Jinput.
  • Y una muy buena referencia para programar juegos en Java es el libro Killer Game Programming in Java, disponible por completo en la Web, continuamente actualizado y con un montón de ejemplos de código. 


Y, para finalizar, Java además de proporcionar una interfaz para procesar eventos de teclado también proporciona una para procesar eventos del ratón. ¿A alguien se le ocurre cómo se puede llamar la interfaz?

jueves, 19 de mayo de 2011

Enlazar una librería con su documentación


Hay veces en las que tenemos por separado el fichero jar de una librería y otro fichero con la documentación de dicha librería.

Eclipse nos permite asociar la documentación de un jar con el mismo de una forma fácil.

Hay que ir a: Project -> Properties -> Jaba Build Path -> Libraries. Si desplegamos el jar al que queramos añadir la documentación, nos encontraremos con algo como lo que aparece en la figura.

Al seleccionar Javadoc location y hacer click en Edit... nos aparece un formulario en el que podemos elegir la localización de la documentación del jar, ya sea en una URL o en un archivo del ordenador o del workspace.

Al seleccionar una opción u otra, tenemos la opción de validar si la selección ha sido correcta con el botón Validate....

Una vez asociada la documentación con el jar, podemos beneficiarnos de tener la documentación del mismo integrada dentro del Eclipse.

De la misma manera, también podemos asociar el código fuente de un jar a un jar en concreto. ¿Para qué creéis que puede valer esto? 

jueves, 5 de mayo de 2011

Puntos clave del tema 4

Estos son los puntos clave del tema 4:
  • Documentación con Javadoc
  • Tipos Abstractos de Datos (TADs)
    • Qué es un TAD
    • Ejemplos de TADs
      • Pila
      • Cola
      • Pila acotada

jueves, 28 de abril de 2011

Orden de complejidad de algoritmos a simple vista

Esta gráfica muestra de un vistazo la importancia de la complejidad del código que implementemos.

A pesar de que se muestran valores cercanos al eje de coordenadas, se puede comprobar fácilmente la penalización en tiempo de ejecución según aumenta la complejidad.

viernes, 15 de abril de 2011

Puntos clave del tema 3

Estos son los puntos clave del tema 3:

  • Manejo de situaciones anómalas
    • Aserciones
    • Excepciones
      • Lanzamiento y captura
      • Definición de excepciones
  • Interfaces
  • Herencia y polimorfismo
    • Herencia de clases
    • Polimorfismo
    • Clases abstractas
  • Genéricos

viernes, 8 de abril de 2011

Serialización de objetos Java

Los objetos que creamos en Java no sólo viven en la memoria del ordenador. Java permite convertir  un objeto en memoria en un grupo de bytes para después convertir de nuevo ese grupo de bytes en un objeto en memoria (lo que se llama serializar y deserializar, respectivamente).

Las utilidades de esto son todas las que se nos ocurran. Desde persistir objetos en ficheros para utilizarlos más allá de la ejecución del programa a enviar un objeto a través de una red para utilizarlo en un programa Java en otro ordenador.

Para indicar que una clase es serializable, ha de implementar la interfaz Serializable (como no). Y, en caso de que uno de los atributos de la clase sea a su vez un objeto, la clase de dicho objeto tiene también que implementar dicho interfaz.

Tenía pensado contar más detalles acerca de la serialización, pero me he encontrado con una guía muy buena sobre la serialización en Java en ChiWiki que incluye lo que pensaba contar y más.

Y, por su puesto, nunca viene de más consultar la documentación de Java sobre serialización.

viernes, 1 de abril de 2011

Más allá del println

Si queréis llevar vuestra depuración de código a otro nivel, sin tener que recurrir continuamente al System.out.println, podéis utilizar una librería de manejo de trazas.

Estas librerías os permiten manejar trazas de ejecución de los programas que hagáis, evitando mostrar siempre los mensajes por la consola, y además definen distintos niveles de mensajes para poder elegir con qué detalle se quiere almacenar la traza.

El propio Java viene con un manejador de trazas (Logger), no obstante el más utilizado es Log4J y es el que os voy a presentar a continuación.

Para utilizar Log4J en un proyecto, lo primero que hay que hacer es incluir en dicho proyecto el jar con las librerías de Log4J que os podéis descargar de la página del proyecto.

El funcionamiento básico es definirse un objeto de tipo Logger llamando a su constructor y pasándole como parámetro el nombre que le queramos dar (si en vez de un nombre le pasamos una clase, utilizará el nombre de la clase).

Logger miLogger = Logger.getLogger("programa.logger"); 

Después tenemos que configurar cómo queremos manejar la traza. Esto se puede hacer o utilizando un fichero de configuración o desde el mismo código. Lo más recomendable es utilizar un fichero de configuración; no obstante, para este ejemplo utilizaremos el configurador por defecto que nos muestra las trazas de todos los niveles por la consola.

BasicConfigurator.configure();  

A partir de aquí, podremos utilizar distintos métodos para almacenar nuevas trazas con distintos niveles. Log4J tiene los siguientes niveles de traza (definidos como constantes de la clase org.apache.log4j.Level):

  • FATAL. Errores serios que harán que la aplicación interrumpa su ejecución 
  • ERROR. Errores con los que la aplicación podría continuar su ejecución 
  • WARN. Situaciones potenciales de error 
  • INFO. Mensajes generales de diagnóstico del progreso de la aplicación 
  • DEBUG. Mensajes específicos de diagnóstico del progreso de la aplicación 
  • TRACE. Mensajes mucho más específicos sobre la aplicación

Y cada uno de dichos niveles tiene un método que almacena una traza en dicho nivel.

public void debug(Object message) 

Si quisiéramos mostrar sólo a partir de cierto nivel, se podría también indicar tanto en el código como en el fichero de configuración. Por ejemplo la siguiente linea mostraría sólo las trazas de nivel INFO y superiores (WARN, ERROR y FATAL).

logger.setLevel(Level.INFO);

Si ejecutamos el siguiente ejemplo

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;

public class ClaseEjecutable {

 public static void main(String[] args) {
  Logger miLogger = Logger.getLogger("programa.logger");

     BasicConfigurator.configure();

  miLogger.info("Inicio de la ejecución");

  String cadena = "Cadena de texto";
  int numero = 1;

  cadena = cadena + numero;

  if (cadena.equals("Cadena de texto1")){
   System.out.println("La cadena calculada es: " + cadena);
   miLogger.debug("La concatenación ha funcionado");
  } else {
   miLogger.debug("La concatenación no ha funcionado");
  }


  miLogger.info("Fin de la ejecución");
 }

}

podremos ver por la consola la siguiente salida donde se muestran las distintas trazas y sus correspondientes niveles.

0 [main] INFO programa.logger - Inicio de la ejecución 
La cadena calculada es: Cadena de texto1 
1 [main] DEBUG programa.logger - La concatenación ha funcionado 
1 [main] INFO programa.logger - Fin de la ejecución  

Una vez hemos acabado de depurar el programa, no hace falta que eliminemos ni una linea de código, con poner el nivel ERROR ya solo nos aparecerán aquellas trazas que muestren errores en el programa.

Log4J permite hacer muchas más cosas que las que se mencionan aquí, con lo que os animo echar un vistazo a su documentación y a los tutoriales disponibles en la Web.

¿Qué os parece esta alternativa al println?
¿Creéis que la usaréis en un futuro cercano?