【问题标题】:Progress bar in pyqt not updating properly for reading filepyqt中的进度条没有正确更新以读取文件
【发布时间】:2017-06-02 10:18:49
【问题描述】:

我在一个应用程序中有一个进度条,它应该在文件被读取时进行,但它根本没有按照我设定的条件进行更新。看来我需要给负责更新进度条的变量一个显式值而不是另一个变量。请看下面的代码,特别是我的loadfile函数。

import sys
from PyQt4 import QtCore, QtGui
import subprocess
from time import sleep

class AppView(QtGui.QDialog):

    def __init__(self, parent=None):
        super(AppView, self).__init__(parent)
        self.resize(400, 400)
        self.buttonStart = QtGui.QPushButton(self)
        self.buttonStart.setText("Start")
        self.buttonStart.clicked.connect(self.start)

        self.progress = QtGui.QProgressBar(self)
        self.progress.setGeometry(200, 80, 250, 20)
        verticalLayout = QtGui.QVBoxLayout(self)
        verticalLayout.addWidget(self.buttonStart)
        verticalLayout.addWidget(self.progress)

    def line_count(self):
        p = subprocess.Popen(['wc', '-l', 'xfile'], stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)
        result, err = p.communicate()
        if p.returncode != 0:
            raise IOError(err)
        return int(result.strip().split()[0]) #returns 407 lines

    def start(self):
        self.loadfile()

    def loadfile(self):
        x = 100/self.line_count()
        loading = 0

        file_in = "xfile"
        with open(file_in) as f:
            for line in f:
                #sleep(0.1)
                print line
                loading += x
                #loading += 0.245700246
                self.progress.setValue(loading)

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    appview = AppView()
    appview.show()
    sys.exit(app.exec_()) 

但是,如果我像这样loading += 0.245700246 设置加载,它可以工作。我不明白为什么 loading += x 不做同样的事情,因为它也返回 0.245700246。

另一个问题是,当它工作并且进度条正在更新时,整个 UI 都被冻结了。就好像它正在使用所有的 ui 线程,我还不知道如何解决这个问题。我无法关闭应用程序或执行任何其他操作。

【问题讨论】:

    标签: python python-2.7 pyqt pyqt4


    【解决方案1】:

    你不能在主线程中更新你的进度条,你必须创建另一个来做到这一点

    class Progress(QtCore.QThread):
        def __init__(self):
            QtCore.QThread.__init__(self)
    
        def run(self):
            self.emit(QtCore.SIGNAL('__updateProgressBar(int)'), 0) ## Reset progressbar value
            file_in = "xfile"
            loading = 0
            with open(file_in) as f:
                fl_content = f.read().splitlines()
                total_lines = len(fl_content)
                for i, line in enumerate(fl_content):
                    print line
                    self.emit(QtCore.SIGNAL('__updateProgressBar(int)'), i*100/total_lines)
                    sleep(0.1)
    
    class AppView(QtGui.QDialog):
    
        def __init__(self, parent=None):
            super(AppView, self).__init__(parent)
            self.resize(400, 400)
            self.buttonStart = QtGui.QPushButton(self)
            self.buttonStart.setText("Start")
            self.buttonStart.clicked.connect(self.start)
    
            self.progress = QtGui.QProgressBar(self)
            self.progress.setGeometry(200, 80, 250, 20)
            verticalLayout = QtGui.QVBoxLayout(self)
            verticalLayout.addWidget(self.buttonStart)
            verticalLayout.addWidget(self.progress)
    
            self.progressView = Progress()
            self.connect(self.progressView, QtCore.SIGNAL("__updateProgressBar(int)"), self.__updateProgressBar)
    
        @QtCore.pyqtSlot(int)
        def __updateProgressBar(self, percent):
            self.progress.setValue(percent)
    
        def start(self):
            self.progressView.start()
    

    【讨论】:

    • 你知道如何在 python3 和 pyqt5 中做同样的事情吗?
    【解决方案2】:

    你的例子的问题是这一行:

    x = 100/self.line_count()
    

    在 Python2 中,x 将始终计算为零,无论您是否使用整数除法。要获得浮点值,其中一个操作数必须是浮点数:

    x = float(100) / self.line_count()
    

    该更改是使您的示例正常工作所需的全部内容。你不需要使用单独的线程,因为你只是在做 IO 操作。 Python 在 IO 操作期间释放 GIL,因此 GUI 不会被阻塞。

    您的loadfile 方法可以像这样细化一点:

    def loadfile(self):
        file_in = 'xfile'
        # no need to call out to wc for line count
        x = float(100) / os.path.getsize(file_in)
        # start at 1 so the progress bar goes to 100%
        loading = 1
        with open(file_in) as f:
            for line in f:
                # use line length to calculate progress
                loading += x * len(line)
                self.progress.setValue(loading)
                # this may help to keep the gui responsive
                QtGui.qApp.processEvents()
    

    【讨论】:

    • 谢谢,这说明了很多事情
    • 进度条没问题,但是gui仍然被锁定,而它以这种方式工作。
    • @Tata​​kaiWasumi。这很奇怪,因为它对我来说很好用。如果进度条正在更新,则 gui 未被阻止。
    • @Tata​​kaiWasumi。 PS:我在 loadfile 方法中添加了一个额外的行,这应该有助于保持 gui 响应。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-04
    • 1970-01-01
    • 2022-12-30
    • 1970-01-01
    相关资源
    最近更新 更多