操作期间进度条未更新

9
在我的Python程序中,我使用GTK进度条显示上传进度,但我遇到的问题是直到上传完成,进度条才会显示任何活动,然后突然指示上传完成。我使用pycurl进行http请求...我的问题是 - 我需要一个多线程应用程序来同时上传文件和更新GUI吗?还是我犯了其他错误?
提前感谢!
5个回答

13

我将引用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 将不起作用)。
另一种解决方案是使用 gtk 空闲函数,每当 gtk 主循环没有任务可执行时便会调用它们。因此,gtk 控制,而空闲函数则需要处理一些工作。如果还有更多工作要做,则它应该返回 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
很可能问题在于您的进度回调函数中,我猜测您正在更新进度条,但没有手动调用更新显示即运行GUI的事件循环。这只是猜测,如果您能提供更多代码,可能会更容易进一步缩小问题范围。
需要手动更新显示的原因是您的主线程也在执行上传操作,这就是它被阻塞的地方。

0

是的,你可能需要并发,线程是一种方法,但如果你使用线程,请使用像这样的方法:http://unpythonic.blogspot.com/2007/08/using-threads-in-pygtk.html,它将抽象出痛苦,并允许你专注于重要方面。

(我由于懒惰没有重复那篇博客文章中的所有内容,因此成为社区维基)。


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也会使使用套接字变得更加轻松。


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)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接