【问题标题】:Updating ProgressBar with a label periodically定期更新带有标签的 ProgressBar
【发布时间】:2019-07-23 19:37:14
【问题描述】:

我正在开发一个需要使用 QProgressBar 让用户了解进度的应用程序。但是,我不想在步骤中更新进度条,而是使用 setMaximum(0) 在进度条上显示“忙碌”指示器并更新 QLabel 以显示当前阶段。我这样做是为了让一切变得简单。

这里有一个模拟 UI 来简化解释。

这是对应的代码:

class TestWindow(QMainWindow):
  def __init__(self):
    super().__init__()
    relpath = 'ui/test.ui'
    uifile = join(dirname(sys.argv[0]), relpath)
    uic.loadUi(uifile, self)
    self.pushButton.clicked.connect(self.start_updating)

  def start_updating(self):
    self.progressBar.setMaximum(0)
    self.label.setText("Func 1")
    sleep(3) # in real app do something here
    self.label.setText("Func 2")
    sleep(3) # in real app do something else here
    self.label.setText("Func 3")


if __name__ == "__main__":
  app = QApplication(sys.argv)
  window = TestWindow()
  window.show()
  sys.exit(app.exec_())

如果我运行它,那么只会显示 QLabel 的最后一个状态(“Func 3”),并且在最后一次更新标签文本之前,进度条上不会显示“忙碌”模式。谁能帮我理解为什么这不起作用以及是否有更好的方法来定期更新标签?

【问题讨论】:

    标签: python python-3.x pyqt pyqt5


    【解决方案1】:

    您不应在 GUI 线程中执行繁重的任务,因为它们会阻止事件循环阻止 GUI 更新,例如在您的情况下标签未更新。相反,您必须在另一个线程中执行该任务并通过信号发送更新 GUI 的信息:

    import os
    import sys
    import time
    
    from PyQt5 import QtCore, QtGui, QtWidgets, uic
    
    
    class Worker(QtCore.QObject):
        textChanged = QtCore.pyqtSignal(str)
        started = QtCore.pyqtSignal()
        finished = QtCore.pyqtSignal()
    
        @QtCore.pyqtSlot()
        def run_task(self):
            self.started.emit()
            self.textChanged.emit("Func 1")
            time.sleep(3)  # in real app do something here
            self.textChanged.emit("Func 2")
            time.sleep(3)  # in real app do something else here
            self.textChanged.emit("Func 3")
            self.finished.emit()
    
    
    class TestWindow(QtWidgets.QMainWindow):
        def __init__(self):
            super().__init__()
            relpath = "ui/test.ui"
            current_dir = os.path.dirname(os.path.realpath(__file__))
            uifile = os.path.join(current_dir, relpath)
            uic.loadUi(uifile, self)
    
            thread = QtCore.QThread(self)
            thread.start()
    
            self.m_worker = Worker()
            self.m_worker.moveToThread(thread)
            self.m_worker.started.connect(self.onStarted)
            self.m_worker.finished.connect(self.onFinished)
            self.m_worker.textChanged.connect(self.update_label)
    
            self.pushButton.clicked.connect(self.m_worker.run_task)
            self.progressBar.setValue(0)
    
        @QtCore.pyqtSlot()
        def onStarted(self):
            self.progressBar.setMaximum(0)
            self.pushButton.setEnabled(False)
    
        @QtCore.pyqtSlot()
        def onFinished(self):
            self.progressBar.setMaximum(1)
            self.progressBar.setValue(1)
            self.pushButton.setEnabled(True)
    
        @QtCore.pyqtSlot(str)
        def update_label(self, text):
            self.label.setText(text)
    
    
    if __name__ == "__main__":
        app = QtWidgets.QApplication(sys.argv)
        window = TestWindow()
        window.show()
        sys.exit(app.exec_())
    

    【讨论】:

    • 谢谢@eyllanesc。这解释得很好,它对我有用。我打算使用相同的进度条来显示从 GUI 执行的不同任务的状态,那么我应该为每个任务创建单独的工作线程吗?这里的最佳做法是什么?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多