Oferta de temporada, cualquier libro a US$5

martes, 26 de octubre de 2010

Swing: Componentes enlazados a un bean

La mejor manera de tener sincronizado un control swing con un javabean es utilizando enlaces (binding). La manera común y poco profesional es utilizar los set  y gets de cada atributo de un bean para asociar a cada componente.

//...
nombreTF.setValue(persona.getNombre());
edadTF.setValue(persona.getEdad());
//... etc
y si son 80 campos, nadie querra hacerle mantenimiento.

Aquí es donde entran los enlaces. Mostraremos un ejemplo con NetBeans para enlazar los componentes de un formulario con un JavaBean.

Este tip es aporte de Fernando Rodelo Mármol, seguidor de este blog, y amigo.

Creando el JavaBean

Primero debemos crear una clase Java. La llamaremos Persona.

Luego, crearemos tres propiedades llamadas nombre, edad y sexo. Pero lo haremos utilizando NetBeans de la siguiente manera.

  1. Clic derecho sobre el código del editor, justo dentro de la clase Persona y seleccionar "Insert code"
  2. Seleccionar "Add property".
  3. Con esto se mostrará un editor para crear una nueva propiedad, al cual haremos los siguientes cambios
    • En el campo name escribimos el nombre de la nueva propiedad: nombre
    • En el campo type indicamos el tipo de la propiedad: String
    • Activamos la opción "Bound". En ese momento se mostrará el campo la declaración de una constante llamada PROP_NOMBRE con el valor "nombre". Esto es para asociar la variable "nombre" con el escuchador (listener) del JavaBean.

  4. Clic en "ok" para aceptar esta propiedad. Repetir la misma operación con los demás campos.
Para el caso de la propiedad "sexo", consideremos utilizar dos propiedades de tipo boolean llamadas "hombre" y "mujer".

Veamos el código generado. De no existir el IDE, deberiamos escribir todo el código. Bastante ¿no?

    Enlazando JavaBean con formulario swing

    Ahora que ya tenemos el JavaBean con su respectivo manejador de cambios de propiedades, debemos crear en el formulario swing una propiedad de tipo Persona. Además, esta propiedad debe tener sus respectivos get/set.


    En el panel de diseño del formulario vamos a enlazar cada control con cada propiedad de la propiedad persona.

    Hacemos clic-derecho en el control donde irá el nombre, y seleccionamos "bind > Text" que significa "enlazar el texto del control"

    El IDE nos mostrará una ventana de diálogo para configurar el enlace del control. Aquí primero seleccionamos en la opción "Binding Source" de dónde se va a tomar el campo a enlazar. Como hemos declarado nuestra propiedad "persona" dentro del formulario, entonces seleccionamos "Form"


    En la parte inferior se mostrará un listado de los componentes del formulario. Buscamos a "persona", abrimos el nodo y seleccionamos (en este caso) la propiedad "nombre".


    Hacemos clic en "OK" y repetimos la acción en las demás propiedades.

    Es importante recalcar que la propiedad del JavaBean debe tener el mismo tipo del que maneja el control. El tipo de control lo podemos ver en la parte superior de la ventana de diálogo. Por ejemplo, el del JTextField dice "Bind property text (java.lang.String) to:"

    Probando guardar el JavaBean

    Ahora, cada vez que escribamos algo en los controles, se guardarán directamente en el JavaBean. ¿No me creen? Bueno, hagamos la siguiente prueba: después de escribir los valores, guardemos los valores del JavaBean en un archivo XML.

    Para ello, programaremos el siguiente código en el botón "Guardar".
    
    XMLEncoder encoder = new XMLEncoder(
                             new BufferedOutputStream(
                                 new FileOutputStream(ARCHIVO_XML)));
    encoder.writeObject(persona);
    encoder.close();
    
    

    Donde la variable ARCHIVO_XML es un String que contiene el nombre del archivo a guardar.

    Ahora, hagamos la prueba: llenemos el formulario, y hagamos clic en Guardar.


    Y veamos el archivo XML que guardó.

    Usé el XMLEncoder para evitar todo un manejo de base de datos para este ejemplo.

    Probando mostrar controles actualizados

    Me dirán "ok Diego, ya sé que el bean está asociado a los controles.. escribo en el control y lo guarda en el JavaBean.. hice hasta  un debug y me funciona.. pero si modifico el JavaBean ¿cómo refresco el contenido de los controles? "

    Bueno, esto es automático. Basta que se haga un cambio en el JavaBean Persona, los controles se actualizan automáticamente.

    Hagamos esta prueba: en el botón "Nuevo" escribimos el siguiente código:
    
    persona.setNombre("");
    persona.setEdad(0);
    persona.setMujer(false);
    persona.setHombre(false);
    buttonGroup1.clearSelection();
    
    

    Funciona...!!

    Nota: no intentar hacer
    persona=new Persona();
    porque se crearía otro objeto y el enlace con el control se pierde. Entonces, si hay 80 campos ¿tengo que hacer esto por todos los campos? Uhmm.... sí.

    Cuando usamos enlaces (bindings) debemos considerar que el formulario tiene un objeto JavaBean asociado al mismo formulario... es como el "alma" del formulario.... funciona como el "objeto actual" del formulario. Lo que podemos hacer es usar una variable temporal para copiar sus valores al JavaBean del formulario. Así manejamos el temporal, creamos, alteramos etc.. pero solo le damos una copia de este temporal al JavaBean.

    Cargando el JavaBean guardado

    Volviendo a nuestro ejemplo.. si ya hemos guardado el JavaBean en un XML, hemos cerrado y volvemos a ejecutar el formulario... y ahora queremos cargar lo que hemos guardado ¿qué hacemos? Bueno, usamos el XMLDecoder, cargamos el valor en un objeto temporal y copiamos los valores al JavaBean persona.

    "Pero Diego.. ¿si son 80 campos?" Ok ok.. vamos a valernos de una biblioteca de Apache Commons para copiar las propiedades de un objeto a otro. Esta biblioteca se llama BeanUtils y el método se llama BeanUtils.copyProperties().

    
    XMLDecoder decoder = new XMLDecoder(
                             new BufferedInputStream(
                                 new FileInputStream(ARCHIVO_XML)));
    Persona $persona = (Persona) decoder.readObject();
    decoder.close();
    BeanUtils.copyProperties(persona, $persona);
    
    

    Ahora sí.. ya funciona....

    ¿Y para el botón "Nuevo"?.. lo mismo, solo que no cargaremos un XML, sino copiaremos las propiedades de un objeto nuevo.

    
    Persona $persona = new Persona();
    BeanUtils.copyProperties(persona, $persona);
    buttonGroup1.clearSelection();
    
    

    Proyecto de ejemplo

    Y no iba a faltar el proyecto utilizado en este post.

    http://kenai.com/projects/apuntes/downloads/download/ejemplos%252Fswing%252FSwingListenerApp.tar.gz

    Espero que les sea de utilidad.