进度条在操作期间不更新

Pra*_*nav 7 python gtk user-interface pygtk progress-bar

在我的python程序中将文件上传到互联网,即时通讯使用GTK进度条显示上传进度.但是我面临的问题是进度条在上传完成之前没有显示任何活动,然后它突然表示上传完成.即时通讯使用pycurl来发出http请求...我的问题是 - 我是否需要一个多线程应用程序来上传文件并同时更新gui?或者是否还有其他错误?

提前致谢!

Man*_*ron 13

我将引用PyGTK FAQ:

您已在窗口中创建了一个进度条,然后开始运行一个可以完成某些工作的循环:

while work_left:
    ...do something...
    progressbar.set_fraction(...)
Run Code Online (Sandbox Code Playgroud)

您会注意到窗口甚至没有显示,或者如果它出现,进度条将保持冻结状态直到任务结束.解释很简单:gtk是事件驱动的,你正在从gtk主循环中窃取控制权,从而阻止它处理正常的GUI更新事件.

最简单的解决方案是每次进度改变时暂时将控制权交还给gtk:

while work_left:
    ...do something...
    progressbar.set_fraction(...)
    while gtk.events_pending():
        gtk.main_iteration()
Run Code Online (Sandbox Code Playgroud)

请注意,使用此解决方案,用户无法退出应用程序(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)
Run Code Online (Sandbox Code Playgroud)

上面的'while'只是一个例子.唯一的规则是它应该在完成一些工作后产生True并且还有更多的工作要做,并且在任务完成时它必须产生False.