Python 四步设置进度条

216 阅读1分钟
  1. 在使用 Python 代码设置四步进度条时,遇到的问题如下:
  • 进度条在开始时会跳动 10 秒左右,然后开始下载并显示进度。
  • 下载完成后,进度条卡住不动,无法进行下一步操作。
  1. 解决方案

答案中给出的解决方案如下:

  • 不要使用 while gtk.events_pending(): gtk.main_iteration() 来更新 GUI,这是不推荐的做法。
  • 可以使用 refresh_gui() 函数来更新 GUI,该函数可以阻塞直到所有待处理事件都被触发。
  • 推荐使用线程来处理耗时操作,而不是继承 Thread 类。

代码示例

import sys
import time
import pygtk
import gtk
import gobject
import threading
import urllib
import urlparse

class WorkerThread(threading.Thread):

    def __init__(self, function, parent, arg=None):
        threading.Thread.__init__(self)
        self.function = function
        self.parent = parent
        self.arg = arg
        self.parent.still_working = True

    def run(self):  # 当执行 "run" 时
        self.parent.still_working = True
        if self.arg is None:
            self.function()
        else:
            self.function(self.arg)

        self.parent.still_working = False

    def stop(self):
        self = None


class MainWindow:
    def __init__(self):
        gtk.gdk.threads_init()
        self.wTree = gtk.Builder()
        self.wTree.add_from_file("gui.glade")
        self.mainWindows()

    def mainWindows(self):
        self.mainWindow = self.wTree.get_object("frmMain")

        dic = {
            "on_btnNext_clicked": self.mainWindowNext,
        }
        self.wTree.connect_signals(dic)

        self.mainWindow.show()
        self.installerStep = 0  # 0 = none, 1 = preinstall, 2 = download, 3 = install info, 4 = install
        # gtk.main()
        self.mainWindowNext()

    def pulse(self):
        self.wTree.get_object("progress").pulse()

        if self.still_working == False:
            self.mainWindowNext()

        return self.still_working

    def preinstallStep(self):
        self.wTree.get_object("progress").set_fraction(0)
        self.wTree.get_object("btnNext").set_sensitive(0)
        self.wTree.get_object("notebook1").set_current_page(0)
        self.installerStep = 1
        WT = WorkerThread(self.heavyWork, self)  # Would do a heavy function here like setup some thing
        WT.start()

        gobject.timeout_add(75, self.pulse)

    def downloadStep(self):
        self.wTree.get_object("progress").set_fraction(0)
        self.wTree.get_object("btnNext").set_sensitive(0)
        self.wTree.get_object("notebook1").set_current_page(0)
        self.installerStep = 2
        urllib.urlretrieve('http://mozilla.mirrors.evolva.ro//firefox/releases/3.6.3/win32/en-US/Firefox%20Setup%203.6.3.exe', '/tmp/firefox.exe', self.updateHook)

        self.mainWindowNext()

    def updateHook(self, blocks, blockSize, totalSize):
        percentage = float(blocks * blockSize) / totalSize
        if percentage > 1:
            percentage = 1

        self.wTree.get_object("progress").set_fraction(percentage)

        gtk.main_iteration_do(block=False)

    def installInfoStep(self):
        self.wTree.get_object("btnNext").set_sensitive(1)
        self.wTree.get_object("notebook1").set_current_page(1)
        self.installerStep = 3

    def installStep(self):
        self.wTree.get_object("progress").set_fraction(0)
        self.wTree.get_object("btnNext").set_sensitive(0)
        self.wTree.get_object("notebook1").set_current_page(0)
        self.installerStep = 4

        WT = WorkerThread(self.heavyWork, self)  # Would do a heavy function here like setup some thing
        WT.start()

        gobject.timeout_add(75, self.pulse)

    def mainWindowNext(self, widget=None):
        if self.installerStep == 0:
            self.preinstallStep()
        elif self.installerStep == 1:
            self.downloadStep()
        elif self.installerStep == 2:
            self.installInfoStep()
        elif self.installerStep == 3:
            self.installStep()
        elif self.installerStep == 4:
            sys.exit(0)

    def heavyWork(self):
        time.sleep(10)


if __name__ == '__main__':
    MainWindow()
    gtk.main()