PyQt5:在运行时更新标签

PyQt5: Update labels inrun time

我在 运行 期间循环更新标签时遇到问题。我想我需要使用信号等等,但我已经尝试了我现在能想到的一切。我希望我的程序做什么:

当我单击按钮时,应该会启动一个循环 运行 一些需要一些时间的函数。当函数处于 运行ning 时,相应的标签应更新其文本以显示 "running",完成后应显示 "done" 并继续下一个功能。我已经创建了一些代表我所追求的虚拟代码!

我用一个只需要一些时间的虚拟函数来表示我的函数。

import sys
from PyQt5.QtWidgets import *
import time

class Example(QWidget):

    def __init__(self):
        super().__init__()

        self.initUI()


    def initUI(self):
        # Set up an example ui
        qbtn = QPushButton('Click', self)
        qbtn.clicked.connect(self.changeLabels)
        qbtn.resize(qbtn.sizeHint())
        qbtn.move(100, 50)
        # Add labels
        self.labels = list()
        self.labels.append(QLabel("Lbl1", self))
        self.labels[-1].setFixedSize(50, 20)
        self.labels.append(QLabel("Lbl2", self))
        self.labels[-1].setFixedSize(50, 20)
        self.labels[-1].move(0, 20)
        self.labels.append(QLabel("Lbl3", self))
        self.labels[-1].setFixedSize(50, 20)
        self.labels[-1].move(0, 40)

        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('Test')
        self.show()

    def changeLabels(self):
        # Loop over all labels. For each label a function will be executed that will take some time. In this case
        # I represent that with a dummy function to just take time. While the function is running the label should say
        # "running" and when its finished it should say "done".
        for lbl in self.labels:
            orgTxt = lbl.text()
            lbl.setText("%s Running" % orgTxt)
            self.dummyFunction()
            lbl.setText("%s Done" % orgTxt)

    def dummyFunction(self):
        time.sleep(1)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

GUI不支持阻塞任务,因为GUI需要一些时间来更新window的一些属性,一个可能的解决方案是使用一个新的线程并实现dummy函数,在下面的例子中使用信号显示实现。如果您的真实函数更新了任何 GUI 视图,您不应该直接在线程中执行它,您应该通过信号来执行它。

class DummyThread(QThread):
    finished = pyqtSignal()
    def run(self):
        time.sleep(1)
        self.finished.emit()

class Example(QWidget):
    [...]
    def changeLabels(self):
        for lbl in self.labels:
            orgTxt = lbl.text()
            lbl.setText("%s Running" % orgTxt)
            thread = DummyThread(self)
            thread.start()
            thread.finished.connect(lambda txt=orgTxt, lbl=lbl : lbl.setText("%s Done" % txt))

一种更简单的方法是调用 QApplication.processEvents() 以强制 QT 处理队列中存在的所有事件。但是 UI 不会像其他答案中所述的另一个线程执行工作并向主线程发送信号那样响应。