在我的Python程序中,我使用GTK进度条显示上传进度,但我遇到的问题是直到上传完成,进度条才会显示任何活动,然后突然指示上传完成。我使用pycurl进行http请求...我的问题是 -
我需要一个多线程应用程序来同时上传文件和更新GUI吗?还是我犯了其他错误?
提前感谢!
提前感谢!
我将引用PyGTK FAQ的内容:
您在窗口内创建了一个进度条,然后开始运行一段执行一些工作的循环:
while work_left:
...do something...
progressbar.set_fraction(...)
您会注意到窗口甚至没有显示出来,或者如果显示了,进度条仍然停滞不前,直到任务结束。原因很简单:gtk是事件驱动的,而您正在从gtk主循环中夺取控制权,从而阻止它处理正常的GUI更新事件。
最简单的解决方案是每次更改进度时暂时将控制权交还给gtk:
while work_left:
...do something...
progressbar.set_fraction(...)
while gtk.events_pending():
gtk.main_iteration()
请注意,使用此解决方案时,用户在执行 heavy_work 期间无法退出应用程序(由于新循环 [gtk.main_iteration()] 的存在,gtk.main_quit 将不起作用)。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)
上面的 'while' 只是一个例子。唯一的规则是它应该在完成一些工作后产生 True,仍有更多工作要做,并且在任务完成时必须产生 False。
是的,你可能需要并发,线程是一种方法,但如果你使用线程,请使用像这样的方法:http://unpythonic.blogspot.com/2007/08/using-threads-in-pygtk.html,它将抽象出痛苦,并允许你专注于重要方面。
(我由于懒惰没有重复那篇博客文章中的所有内容,因此成为社区维基)。
如果您对pycurl没有执念,那么可以选择使用GObject的IO观察器。
http://pygtk.org/pygtk2reference/gobject-functions.html#function-gobject--io-add-watch
使用这个方法,您可以将文件上传与正常的PyGTK事件循环交错进行,并且甚至可以在IO监视回调中执行set_progress调用。如果您正在将所有上传工作转移到pycurl上,那么这并不是真正可行的,但是如果您只是通过HTTP上传文件,则io_add_watch也会使使用套接字变得更加轻松。
#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)