PyQt5:更新标签的运行时间

时间:2018-01-24 07:24:33

标签: python pyqt pyqt5 qlabel

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

当我点击按钮时,循环应该开始运行一些需要一些时间的功能。当函数运行时,相应的标签应更新其文本以说明"运行"当它完成时应该说"完成"并继续下一个功能。我已经创建了一些代表我之后的虚拟代码!

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

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_())

2 个答案:

答案 0 :(得分:1)

GUI不支持阻塞任务,因为GUI需要一些时间来更新窗口的某些属性,可能的解决方案是使用新线程并实现虚拟函数,在下面的示例中,实现与使用一起显示信号如果你的真实函数更新了任何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))

答案 1 :(得分:0)

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