sábado, diciembre 23, 2006

JDK 1.6: La clase SwingWorker con ejemplos

Lo prometido es deuda, así que desarrollaré un pequeño ejemplo para demostrar cómo se utiliza la clase SwingWorker.
El ejemplo más obvio que se me ocurre es el un JProgressBar que de actualice de forma automática.
Existen dos formas de realizarlo, la tradicional (compartir al hilo el JProgressBar) y la nueva, que es utilizando un modelo de eventos para realizar la actualización. Vamos a usar las dos para marcar diferencias.

La imagen de la derecha refleja como se verá el programa andando. Ya pueden intuir que sucederá cuando se haga click en "Start Worker" y en "Cancel Worker". Sin embargo lo importante es cómo se actualizará la barra de progreso y el JLabel de "Completado ...".
Estos dos componentes que se actualizarán tienen aspectos bastante interesantes. El JProgressBar se actualiza en "tiempo real", ya que estará accedido por el SwingWorker directamente (esto es, porque estoy declarando el SwingWorker como "inner class"). En cambio, el JLabel de porcentaje, no será accedido por el SwingWorker, sino que su actualización será parte de un evento. En el siguiente diagrama se puede ver un poco más la interacción de los hilos principales del programa.

Ahora bien, el acceso al JProgressBar no es nada novedoso, de hecho probablemente ya lo hayan hecho antes. Lo novedoso aquí es la aparición del Event Dispatch Thread, quien será el encargado ahora de notificar a un "Listener" que ha cambiado alguna propiedad en el SwingWorker. En nuestro caso, tomaremos una propiedad implícita del SwingWorker llamada progress (de tipo entero, rango 0-100, accedido por setProgress(int) y getProgress()).

Ahora veamos un poco el código fuente de esto. El siguiente fragmento muestra la creación y llamada a ejecución de un SwingWorker (trabajador):



La clase que implementa SwingWorker se llama MiWorker. Es bastante intuitivo, invocando a execute(); se inicia la ejecución del Thread. Pero cuidado, el SwingWorker se ejecutará sólo una vez por más invocaciones que hagamos a execute().
Quiero hacer más hincapié en la inner class PropertyChangeListener. El hilo de manejo de eventos de Java será el encargado de invocar el método propertyChange automáticamente cuando el Worker "dispare" una notificación de que ha cambiado alguna propiedad. Esta propiedad puede ser una designada por nosotros (en cuyo caso deberemos invocar a firePropertyChange() en nuestro código) o podemos usar alguna de las 2 propiedades designadas por defecto (progress y state). En este último caso, el mismo worker dispara la notificación al hilo de eventos para que este notifique (asincrónicamente) a los listeners.




En este fragmento se describe la inner class MiWorker. Es aquí donde se realiza todo el proceso. Es nuestro hilo de ejecución. Sólo 1 método es estrictamente requerido, el doInBackGround() quien será el encargado de realizar todo el procesamiento. Eso que ven en la declaración de la clase () es lo que se conoce como Generics, una muy buena utilidad incorporada en la versión 1.5 del JDK. Les recomiendo leer más acerca de este tema en The Java Tutorial.
Si se fijan, estoy accediendo en forma directa al JProgressBar (ojo, esto es posible porque MiWorker es una inner class), sin embargo, no accedo al JLabel. El cambio de este componente se dará de forma asíncrona cuando se invoca una y otra vez a setProgress. Esto está bueno porque no necesariamente se notificará al Listener una y otra vez. Por ejemplo, si se ejecuta muchas veces se notificará el progreso 1, el 2,3,4 pasarán de largo y se notificará el 5, etc..

Ya no puedo extenderme más, así que espero que les sirva, les dejo los fuentes en el siguiente link: worker.rar (6Kb)

Saludos PF

7 Comments:

At 11:54 p. m., Blogger Dalfa said...

Creo que ya lo mencionaste en otro post, pero subiste este ejemplo el alguna url?

 
At 8:40 p. m., Blogger Pablo Frias said...

Gracias por avisar dalfa, ya está arreglado el link.

Saludos
Pablo

 
At 11:08 a. m., Anonymous Anónimo said...

gracias por la explicacion andaba buscando algo asi para mi proyecto de la escuela

 
At 1:03 p. m., Blogger Martosfre said...

Super Pablo, gracias por la info. Estamos en contacto, adelante maestro dios te bendiga. Att: Martosfre

 
At 9:38 a. m., Blogger Scrum Manager said...

Buenas, muchas gracias por el post, muy buena info y con un poco mas de detalle que la de la pagina de sun.
Tengo una consulta para hacerte, resulta que lo estoy usando para un proyecto de la universidad. Tengo un jframe que envia mails, pasa que este proceso de enviar mails demora un tiempo ya que debe conectarse al servidor de mails, preparar el envio, enviar y por ultimo cerrar la conexion con el servidor de mails. Debido a esto el mensaje de que ha sido enviado demora uno 5-7 segundos en aparecer por lo antes mencionado, y me parecio una buena idea utilizar jprogressbar para este fin. Pero para mi desgracia no he encontrado como hacer que el jprogressbar se rellene en la misma medida que el proceso de enviar el mail. Te estaria eternaemente agradecido si pudieras ayudarme

 
At 12:03 p. m., Blogger Pablo Frias said...

Scrum Manager: Creo que te convendría hacer no un jprogressbar de progreso, sino "jugar" un poco para que se muestre como una animación. Esto es debido a que no podemos saber a ciencia cierta cúanto tiempo va a tardar el envío de la información. Sería como hacer una animación en una página web.

 
At 1:35 p. m., Blogger Andi said...

Hola Pablo, se que ya es viejo tu post y me sirvio mucho cuando lo necesite, yo he hecho uno sobre el mismo tema pero haciendo una consulta a una Base de Datos.
Revisalo y si tienes algun alcance por favor me avisas.
http://dairdev.blogspot.com/2010/10/uso-de-swingworker-en-una-aplicacion.html

 

Publicar un comentario

<< Home