La barra de progreso no se actualiza durante la operación

en mi progtwig de python para cargar un archivo en Internet, estoy usando una barra de progreso de GTK para mostrar el progreso de la carga. Pero el problema al que me enfrento es que la barra de progreso no muestra ninguna actividad hasta que se complete la carga, y luego, de repente, indica que la carga se ha completado. Estoy usando pycurl para realizar las solicitudes http … mi pregunta es: ¿necesito tener una aplicación de subprocesos múltiples para cargar el archivo y actualizar simultáneamente la interfaz gráfica de usuario? ¿O hay algún otro error que estoy haciendo?

¡Gracias por adelantado!

Voy a citar las preguntas frecuentes de PyGTK :

Ha creado una barra de progreso dentro de una ventana, luego comienza a ejecutar un ciclo que funciona:

while work_left: ...do something... progressbar.set_fraction(...) 

Notará que la ventana ni siquiera aparece, o si lo hace, la barra de progreso permanece congelada hasta el final de la tarea. La explicación es simple: gtk está controlado por eventos, y usted está robando el control del circuito principal de gtk, evitando así que procese eventos de actualización de GUI normales.

La solución más simple consiste en devolver temporalmente el control 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 no funcionaría debido al nuevo bucle [gtk.main_iteration ()]) hasta que finalice el trabajo pesado.

Otra solución consiste en usar funciones inactivas de gtk, que son invocadas por el bucle principal de gtk cuando no tiene nada que hacer. Por lo tanto, gtk está en 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. Se está aprovechando los generadores de Python como funciones inactivas, para hacer que Python conserve 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 ‘while’ de arriba es solo un ejemplo. Las únicas reglas son que debe producir Verdadero después de hacer un poco de trabajo y hay más trabajo que hacer, y debe generar Falso cuando se realiza la tarea.

Lo más probable es que el problema sea que en su callback de progreso, que es donde presumo que está actualizando la barra de progreso, no está haciendo una llamada para actualizar manualmente la pantalla, es decir, ejecutar el ciclo de eventos de la GUI. Sin embargo, esto es solo una especulación, si puede proporcionar más código, podría ser más fácil reducirlo aún más.

La razón por la que necesita actualizar manualmente la pantalla es porque su hilo principal también está realizando la carga, que es donde se está bloqueando.

En Python 2.x los operandos enteros dan como resultado una división entera. Prueba esto:

 #Callback function invoked when download/upload has progress def progress(download_t, download_d, upload_t, upload_d): print 'in fileupload progress' mainwin.mainw.prog_bar.set_fraction(float(upload_d) / upload_t) 

Sí, es probable que necesite la concurrencia, y sí, los subprocesos son un enfoque, pero si utiliza subprocesos, use un método como este: http://unpythonic.blogspot.com/2007/08/using-threads-in-pygtk .html que abstraerá el dolor y le permitirá centrarse en los aspectos importantes.

(No he repetido todo en esa publicación del blog a través de la pereza, de ahí la wiki de la comunidad)

Una opción, si no está casado con pycurl, es usar los observadores de IO de GObject.

http://pygtk.org/pygtk2reference/gobject-functions.html#function-gobject–io-add-watch

Usando esto, puede intercalar la carga del archivo con el bucle de eventos normal de PyGTK, e incluso hacer la llamada a set_progress en su callback IO watch. Si está descargando todo el trabajo para cargar en Pycurl, esto no es realmente posible, pero si solo está cargando un archivo a través de HTTP, io_add_watch hará que el uso de un zócalo sea mucho menos doloroso.