2009-01-30 25 views
8

en mi programa python para cargar un archivo en Internet, estoy usando una barra de progreso GTK para mostrar el progreso de la carga. Pero el problema que estoy enfrentando es que la barra de progreso no muestra ninguna actividad hasta que se completa la carga, y luego indica abruptamente que se completó la carga. estoy usando pycurl para hacer las solicitudes http ... mi pregunta es - ¿Necesito tener una aplicación multiproceso para cargar el archivo y actualizar al mismo tiempo la interfaz gráfica de usuario? o hay algún otro error que estoy haciendo?La barra de progreso no se actualiza durante la operación

¡Gracias de antemano!

Respuesta

12

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.

1

Lo más probable es que en su devolución de llamada de progreso, que supone que está actualizando la barra de progreso, no está realizando una llamada para actualizar manualmente la pantalla, es decir, ejecutar el bucle de evento 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.

0

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) 
0

Sí, es probable que tenga concurrencia, y sí las discusiones son una aproximación, pero si usted hace uso de hilos, por favor utilice un método como éste: http://unpythonic.blogspot.com/2007/08/using-threads-in-pygtk.html cuales abstraerá quitar el dolor, y le permiten centrarse en el 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).

0

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

El uso de este se puede intercalar la carga de archivos con el bucle normal de evento PyGTK, e incluso hacer la llamada set_progress en su IO ver la devolución de llamada. 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.

Cuestiones relacionadas