使用QAction切换启动和停止线程

时间:2016-08-07 01:10:00

标签: multithreading pyqt5 qaction

我目前正在尝试构建一个PyQt5应用程序,它应该包含主GUI,并且在后台应该有一个不同的线程,应该在无限循环中测量某些东西。我想使用QAction或Checkbox启动和停止此线程。

所以说当我按下复选框并且状态为true时,应该启动线程,如果我再次点击它,它应该被停止。

现在实现这个的最佳方法是什么?

目前我正在使用像这样的工作线程:

class Worker(QtCore.QObject):
    def __init__(self):
        super(Worker, self).__init__()
        self._isRunning = True

    def task(self):
        if not self._isRunning:
            self._isRunning = True
        while self._isRunning:
            time.sleep(0.5)
            ... measure ...

    def stop(self):
        self._isRunning = False

并在主线程中使其运行:

self.thread = QtCore.QThread()
self.thread.start()
self.worker = Worker()
self.worker.moveToThread(self.thread)

self.btn_start.clicked.connect(self.worker.task)
self.btn_stopped.clicked.connect(lambda: self.worker.stop())

到目前为止这是有效的。但我并不确信这是最好的方法,如果我能按照描述的方式使用复选框做同样的事情,我也会更喜欢它。

1 个答案:

答案 0 :(得分:1)

目前,您发布的代码不是多线程的。这是因为worker.task()是由主线程中的代码启动的,因此它也将在主线程中运行。您需要使用工作线程的started信号来启动任务,并在工作人员上使用自定义信号来退出线程。

下面的演示脚本应解决这些问题:

import sys, time
from PyQt5 import QtCore, QtWidgets

class Worker(QtCore.QObject):
    finished = QtCore.pyqtSignal()
    messageSent = QtCore.pyqtSignal(str)

    def __init__(self):
        super(Worker, self).__init__()
        self._isRunning = False

    def task(self):
        print('WKR thread:', QtCore.QThread.currentThread())
        self._isRunning = True
        count = 0
        while self._isRunning:
            time.sleep(0.5)
            count += 1
            self.messageSent.emit('count: %s' % count)
        self.finished.emit()

    def stop(self):
        self._isRunning = False

class Window(QtWidgets.QWidget):
    def __init__(self):
        super(Window, self).__init__()
        self.button = QtWidgets.QCheckBox('Test', self)
        self.button.toggled.connect(self.handleButton)
        self.label = QtWidgets.QLabel(self)
        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.label)
        layout.addWidget(self.button)
        self.thread = QtCore.QThread()
        self.worker = Worker()
        self.worker.moveToThread(self.thread)
        self.thread.started.connect(self.worker.task)
        self.worker.finished.connect(self.thread.quit)
        self.worker.messageSent.connect(self.label.setText)

    def handleButton(self, checked=False):
        print('GUI thread:', QtCore.QThread.currentThread())
        if checked:
            self.label.clear()
            self.thread.start()
        else:
            self.worker.stop()

if __name__ == '__main__':

    app = QtWidgets.QApplication(sys.argv)
    window = Window()
    window.setGeometry(800, 150, 200, 50)
    window.show()
    sys.exit(app.exec_())