python - instalar - tkinter ttk
La barra de progreso no se actualiza durante la operaciĆ³n (5)
en mi programa python para subir un archivo a internet, estoy usando una barra de progreso GTK para mostrar el progreso de carga. Pero el problema que estoy enfrentando es que la barra de progreso no muestra ninguna actividad hasta que se complete la carga, y luego indica abruptamente que la carga está completa. Estoy usando pycurl para hacer las solicitudes http ... mi pregunta es: ¿necesito tener una aplicación multiproceso para cargar el archivo y al mismo tiempo actualizar la GUI? o hay algún otro error que estoy haciendo?
¡Gracias por adelantado!
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)
Es muy probable que el problema sea que en su devolución de llamada de progreso, que es donde supongo que está actualizando la barra de progreso, no está realizando una llamada para actualizar manualmente la pantalla, es decir, ejecutar el bucle de eventos de la GUI. Sin embargo, esto solo es una especulación, si puede proporcionar más código, podría ser más fácil limitarlo 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 está bloqueando.
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 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 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 a un nuevo bucle [gtk.main_iteration ()]) hasta que se complete su trabajo heavy_work.
Otra solución consiste en usar las 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 ''while'' de arriba es solo 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á terminada.
Sí, probablemente necesite concurrencia, y sí, los hilos son un enfoque, pero si usa hilos, use un método como este: http://unpythonic.blogspot.com/2007/08/using-threads-in-pygtk .html que abstraerá el dolor y le permitirá enfocarse en los aspectos importantes.
(No he repetido todo en esa publicación de blog a través de la pereza, por lo tanto wiki de la comunidad).
Una opción, si no está casado con pycurl, es utilizar los observadores de IO de GObject.
http://pygtk.org/pygtk2reference/gobject-functions.html#function-gobject--io-add-watch
Con esto puedes intercalar la carga de archivos con el ciclo de eventos PyGTK normal, e incluso hacer la llamada set_progress en tu devolución de llamada de reloj IO. Si está descargando todo el trabajo para subirlo a pycurl, esto no es realmente factible, pero si solo está cargando un archivo a través de HTTP, io_add_watch hará que usar un socket para esto también sea menos doloroso.