PyQt5:在线程中使用计时器

7

问题描述

我正在制作一个收集数据、处理数据、显示数据和一些执行操作(如开启/关闭阀门等)的应用程序。为了练习未来应用程序中时间限制更严格的情况,我想在一个单独的线程中运行数据捕获和处理。

我目前的问题是它告诉我不能从另一个线程开始一个计时器。

当前代码进展

import sys
import PyQt5
from PyQt5.QtWidgets import *
from PyQt5.QtCore import QThread, pyqtSignal

# This is our window from QtCreator
import mainwindow_auto

#thread to capture the process data
class DataCaptureThread(QThread):
    def collectProcessData():
        print ("Collecting Process Data")
    #declaring the timer
    dataCollectionTimer = PyQt5.QtCore.QTimer()
    dataCollectionTimer.timeout.connect(collectProcessData)
    def __init__(self):
        QThread.__init__(self)

    def run(self):
        self.dataCollectionTimer.start(1000);

class MainWindow(QMainWindow, mainwindow_auto.Ui_MainWindow):
    def __init__(self):
        super(self.__class__, self).__init__()
        self.setupUi(self) # gets defined in the UI file
        self.btnStart.clicked.connect(self.pressedStartBtn)
        self.btnStop.clicked.connect(self.pressedStopBtn)

    def pressedStartBtn(self):
        self.lblAction.setText("STARTED")
        self.dataCollectionThread = DataCaptureThread()
        self.dataCollectionThread.start()
    def pressedStopBtn(self):
        self.lblAction.setText("STOPPED")
        self.dataCollectionThread.terminate()


def main():
     # a new app instance
     app = QApplication(sys.argv)
     form = MainWindow()
     form.show()
     sys.exit(app.exec_())

if __name__ == "__main__":
     main()

任何关于如何使这个工作的建议都将受到赞赏!
1个回答

10

您需要将QTimer移动到DataCaptureThread线程中,此外,当run方法结束时,线程也被删除,因此必须避免在不阻塞其他任务的情况下运行该函数。为此,可以使用QEventLoop:

class DataCaptureThread(QThread):
    def collectProcessData(self):
        print ("Collecting Process Data")

    def __init__(self, *args, **kwargs):
        QThread.__init__(self, *args, **kwargs)
        self.dataCollectionTimer = QTimer()
        self.dataCollectionTimer.moveToThread(self)
        self.dataCollectionTimer.timeout.connect(self.collectProcessData)

    def run(self):
        self.dataCollectionTimer.start(1000)
        loop = QEventLoop()
        loop.exec_()

谢谢!在编辑以下行之后,代码可以运行: self.dataCollectionTimer.timeout.connect(self.collectProcessData) 改为 self.dataCollectionTimer.timeout.connect(lambda:self.collectProcessData) 否则会出现错误:TypeError: collectProcessData() takes 0 positional arguments but 1 was given。我不是很明白,因为没有传递参数。 - robotHamster
如果这个答案对你有用,请不要忘记将我的回答标记为正确的。 - eyllanesc
@ellyanesc,如果我在你的答案中添加lambda函数,可以吗? - robotHamster
@robotHamster 也许我忘记放一些信息了,使用以下示例作为测试,它可以正常工作:https://gist.github.com/eyllanesc/1f7cf4b05db060286f60487baa0e6146 - eyllanesc
collectProcessData() 不在单独的线程中运行。在该函数内部放置 time.sleep(10),您会发现它会冻结您的主 GUI。 - Nils
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接