martes, 17 de julio de 2007

Implementando una progress bar en un web panel GeneXus

Hoy me encontré con un problema, que con GeneXus no tiene una solución fácil. En una aplicación full web con GeneXus 9.0, tengo un proceso que puede demorar varios minutos, y mientras el proceso corre en el servidor, no hay forma de que el usuario se entere de lo que está haciendo.

La versión original

En la versión original, lo que tenía era un web panel, que hacía un call a un procedimiento, y cuando el procedimiento terminaba, llamaba a otro web panel. Algo así:

Event 'Accion'
call(PProcesa)
call(HMuestraResultado)
EndEvent

El problema con esta arquitectura es que por más que ponga mensajes en el evento, no se van a mostrar hasta que haya terminado de procesar.

Arquitectura de la solución

La solución fue llamar al procedimiento usando el comando submit, con lo que el procedimiento queda ejecutándose, pero el control vuelve de inmediato al web panel.

El código queda entonces así:

Event 'Accion'
submit(PProcesa, '')
call(HMuestraProgreso)
EndEvent

Además, se implementaron dos procedimientos, uno que devuelve la cantidad a procesar y otro que devuelve la cantidad que fueron procesados hasta el momento.

El web panel MuestraProgreso, invoca a estos dos procedimientos en el evento Start, de forma de saber el porcentaje de avance, y muestra un mensaje "Procesados n de N". Este web panel hace un refresh automático cada 3 segundos, de forma de ir mostrando el progreso. Veamos el código.

Event Start
&Total = udp(PCantidadTotal)
&Procesados = udp(PCantidadProcesados)

if &Procesados >= &Total
call(HMuestraResultado)
else
Form.MetaEquiv.AddItem('refresh', '3')
tbkMensaje.Caption = 'Procesados ' + trim(str(&Procesados, 9, 0)) + ' de ' + trim(str(&Total, 9, 0)) + '.'

do 'Progress bar'
endif
EndEvent // Start

El refresh automático se hace colocando un tag HMTL en el cabezal de la página, en el código es la línea con:

Form.MetaEquiv.AddItem('refresh', '3')

Mostrando una barra de progreso

Para mostrar la barra de progreso (progress bar) se necesita un poco más de código HTML. Hay muchas formas de hacerlo, en este caso elegí usar una tabla con varias celdas que se van pintando de algún color a medida que avanza.

Sub 'Progress bar'
&pbDivisiones = 100
&pbAvance = round(&Procesados * &pbDivisiones / &Total, 0)
tbkProgressBar.Caption = '<table id="ProgressBar" cellpadding="0" cellspacing="0" style="width:100%;" border="1" rules="none"><tr>'
for &i = 1 to &pbDivisiones
if &i <= &pbAvance
&style = ' style="BACKGROUND-COLOR: #005B5B"'
else
&style = ''
endif
tbkProgressBar.Caption += '<td' + &style + '>&nbps;</td>'
endfor
tbkProgressBar.Caption += '</tr></table>'
EndSub // 'Progress bar'

El control tbkProgressBar es un text block que se encuentra en el web form del web panel, y que tiene la propiedad Format = HTML.

El resto de la subrutina se debería poder usar tal cual, sin hacerle modificaciones.

4 comentarios:

  1. Buen articulo. Justo lo que estaba necesitando.

    Es intersante usar un poco de CSS para que se vea mas lindo... Fijate en http://www.davidanaxagoras.com/2005/04/16/track-your-progress-or-lack-thereof/

    ResponderEliminar
  2. Alejandro:

    Está bueno el artículo. Como decía, hay varias formas de hacerlo, yo lo hice con HTML porque fue lo que me resultó más fácil.

    No debería ser difícil hacerlo con CSS, y más teniendo el ejemplo. Lo que te cambia es lo que le asignás al text block en la subrutia.

    Cuando lo tengas hecho, publicalo así lo vemos :)

    ResponderEliminar
  3. Mario Delgado23/10/08 15:49

    Hola Marco como estas

    oye necesito implementa rlo del progressbar en un webpanel genexus pero no entiendo muy bien la metodologia que usas, me puedes ayudar un poco.

    mi correo mdelgado@gsite.com.mx

    espreo ayuda gracias

    ResponderEliminar
  4. hola,
    aunque este blog es bastante viejo, quisiera usar algo similar, creando un user control para dicho proposito, pero no he podido encontrar la forma de saber cuantos registros se han procesado y cuantos se van a procesar, traté de usar variables en session pero al parecer el submit crea una session diferente, ¿de que forma puedo conocer los registros procesados y a procesar?
    Gracias

    ResponderEliminar