在我的python程序中将文件上传到互联网,我使用GTK进度条显示上传进度。但是我面临的问题是进度条在上传完成之前没有显示任何活动,然后它突然表示上传完成。即时通讯使用pycurl来发出http请求...我的问题是 - 我是否需要一个多线程应用程序来上传文件并同时更新gui?或者是否还有其他错误?
提前致谢!
答案 0 :(得分:12)
我要引用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()
请注意,使用此解决方案,用户无法退出应用程序(gtk.main_quit因新循环[gtk.main_iteration()]而无法工作,直到您的heavy_work完成。
另一个解决方案是使用gtk空闲函数,只要它没有任何关系,它就会被gtk主循环调用。因此,gtk处于控制状态,而idle函数必须做一些工作。如果还有更多的工作要做,它应该返回True,否则返回False。
James Henstridge指出了最好的解决方案(没有任何缺点)。它利用python的生成器作为空闲函数,使python自动为我们保留状态。它是这样的:
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。
答案 1 :(得分:1)
更有可能的问题是,在你的进程回调中,我认为你正在更新进度条,你没有调用手动更新显示,即通过GUI的事件循环运行。这只是猜测,如果你能提供更多代码,可能更容易进一步缩小代码。
您需要手动更新显示的原因是因为您的主线程也在执行上传,这是阻止它的位置。
答案 2 :(得分:0)
在python 2.x中,整数操作数导致整数除法。试试这个:
#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)
答案 3 :(得分:0)
是的,您可能需要并发,并且是线程是一种方法,但如果您使用线程,请使用类似这样的方法:http://unpythonic.blogspot.com/2007/08/using-threads-in-pygtk.html这将消除痛苦,并让您专注于重要的方面。
(我没有在博客文章中通过懒惰重复一切,因此社区维基)。
答案 4 :(得分:0)
如果你没有与pycurl结婚,一个选择是使用GObject的IO观察者。
http://pygtk.org/pygtk2reference/gobject-functions.html#function-gobject--io-add-watch
使用此方法,您可以将文件上传与普通的PyGTK事件循环交错,甚至可以在IO监视回调中执行set_progress调用。如果你正在卸载上传到pycurl的所有工作,这实际上是不可行的,但如果你只是通过HTTP上传文件,io_add_watch将使用套接字来减轻这种痛苦。