Voy a citar el PyGTK FAQ:
Se ha creado una barra de progreso dentro de una ventana, a continuación, empieza a correr un bucle que hace algún trabajo:
while work_left:
...do something...
progressbar.set_fraction(...)
Notará que la ventana ni siquiera aparece, o si la barra de progreso se mantiene congelada hasta el final de la tarea. La explicación es simple: gtk está controlado por eventos y está robando el control del bucle principal de gtk, lo que le impide procesar eventos de actualización de GUI normales.
La solución más sencilla consiste en dar temporalmente el control de nuevo a gtk cada vez que se cambia el progreso:
while work_left:
...do something...
progressbar.set_fraction(...)
while gtk.events_pending():
gtk.main_iteration()
Tenga en cuenta que con esta solución, el usuario no puede salir de la aplicación (Gtk.main_quit haría no funciona debido al nuevo ciclo [gtk.main_iteration()]) hasta que se complete su trabajo pesado.
Otra solución consiste en utilizar funciones inactivas de gtk, que son llamadas por el bucle principal de gtk cuando no tiene nada que hacer. Por lo tanto, gtk tiene el control y la función inactiva tiene que hacer un poco de trabajo. Debería devolver True si hay más trabajo por hacer, de lo contrario False.
La mejor solución (no tiene inconvenientes) fue señalada por James Henstridge. Está aprovechando los generadores de python como funciones inactivas, para que python preserve automáticamente el estado para nosotros. Dice así:
def my_task(data):
...some work...
while heavy_work_needed:
...do heavy work here...
progress_label.set_text(data) # here we update parts of UI
# there's more work, return True
yield True
# no more work, return False
yield False
def on_start_my_task_button_click(data):
task = my_task(data)
gobject.idle_add(task.next)
El 'mientras que' anterior es sólo un ejemplo. Las únicas reglas son que debe ceder True después de hacer un poco de trabajo y hay más trabajo por hacer, y debe ceder False cuando la tarea está hecha.