PyQt5 如何在阅读文本行时更新进度条?

PyQt5 How to make updating progress bar when line from text is reading?

我是 Python 和 PyQt 的初学者。我想做简单的 UI - 单击按钮打开文件对话框,接下来选择文本文件并将其逐行添加到列表中。这部分工作正常。当文件有大约 500k 行添加需要一些时间,所以决定做一个进度条。我正在搜索如何执行此操作,这是我的代码:

SIZE = 0
VALUE = 0

class External(QThread):
        countChanged = pyqtSignal(int)
        def run(self):
                while VALUE <= SIZE:
                counter = (VALUE*100/SIZE)
                time.sleep(1)
                self.countChanged.emit(int(counter))

class Ui_MainWindow(object):
        def setupUi(self, MainWindow):
                \... some UI setup ...\
                self.listView = QtWidgets.QListWidget()
                self.pushButton = QtWidgets.QPushButton()
                self.pushButton.clicked.connect(self.openFile)
                self.progressBar = QtWidgets.QProgressBar()
        
        def openFile(self):
                global SIZE
                global VALUE
                openfile = QFileDialog.getOpenFileName(self.pushButton, "Open File", "", "TXT (*.txt)")
                SIZE = os.stat(openfile[0]).st_size
                if not openfile[0] == "":
                        with open(openfile[0], 'r') as f:
                                file_text = f.readlines()
                                self.calc = External()
                                self.calc.countChanged.connect(self.onCountChanged)
                                self.calc.start()
                        for line in file_text:
                                self.listView.addItem(line)
                                VALUE = VALUE + sys.getsizeof(line)

        def onCountChanged(self, counter):
                self.progressBar.setValue(counter)

文本每次都会正确添加到列表中。进度条有时根本不加载,有时加载到百分之几(例如23%),但不显示实时进度,看起来是加载整个列表后添加的进度值。

1) 不确定我是否可以使用 getsizeof() 来检查已经处理了多少数据 - 我应该使用什么来代替?

2) 为什么我的进度条不能正常工作?代码应该是什么样的?

感谢您的关注。

首先,它不显示“实时进度”,因为你整整一秒钟都在睡觉,这不是很“实时”。

然后,你使用的是sys.getsizeof,这是对象的大小,而不是线的大小,所以你必须使用len(line).

进度条结果不准确的原因在于 sleep 错误的尺寸计算:如果尺寸计算正确,它将永远不要退出 while 循环,但由于您实际上得到的 VALUE 将变得比 SIZE and 高得多,您每 1 秒才检查一次,循环退出太早.

最后,也许更好的方法是让线程负责加载(然后使用发出文本的信号填充列表);这将使它更准确,实际上实时。

class Loader(QtCore.QThread):
    lineLoaded = QtCore.pyqtSignal(str)
    def __init__(self, filePath):
        super().__init__()
        self.filePath = filePath

    def run(self):
        with open(self.filePath, 'r') as f:
            for line in f.readlines():
                self.lineLoaded.emit(line)
                sleep(.001)

class Test(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        layout = QtWidgets.QVBoxLayout(self)
        self.listView = QtWidgets.QListWidget()
        layout.addWidget(self.listView)
        self.pushButton = QtWidgets.QPushButton('Load file')
        layout.addWidget(self.pushButton)
        self.progressBar = QtWidgets.QProgressBar()
        layout.addWidget(self.progressBar)

        self.pushButton.clicked.connect(self.loadFile)

    def loadFile(self):
        openfile, _ = QtWidgets.QFileDialog.getOpenFileName(self, "Open File", "", "TXT (*.txt)")
        if not openfile:
            return
        self.progressBar.setMaximum(QtCore.QFileInfo(openfile).size())
        self.loader = Loader(openfile)
        self.loader.lineLoaded.connect(self.loading)
        self.loader.start()

    def loading(self, line):
        self.listView.addItem(line)
        self.progressBar.setValue(self.progressBar.value() + len(line))

一个不相关的建议:您似乎在尝试模仿 pyuic 命令的输出,或者您刚刚编辑了该文件。这是 永远 不应该做的事情(出于各种原因,包括如果您需要更新 UI,您最终会遇到一个非常困难的重新整合过程具有 UI 修改的现有代码)。我建议你阅读更多关于正确 using Designer.
另外,避免像这样使用全局变量,这被认为是不好的做法,很容易导致问题和错误。