在python qt5应用程序中进行线程化的正确模式是什么?

时间:2016-11-10 23:59:07

标签: python multithreading pyqt pyqt5 python-multithreading

我正在尝试编写一个运行时间很长的pyqt5应用程序,但不是CPU密集型进程。我希望能够在不挂起UI的情况下运行它,所以我正在尝试使用线程,但是因为我似乎不能只运行一个线程并在它通过其代码后停止它以便它可以再次运行,我已经尝试设置线程以等待变量在运行之前更改。

我知道这不是在pyqt应用程序中运行长进程的正确模式。

import time
import threading
from PyQt5 import QtWidgets, uic


class MyApp(QtWidgets.QMainWindow):
    _run_thread = False

    def __init__(self):
        QtWidgets.QMainWindow.__init__(self)
        self.ui = uic.loadUi('myapp.ui', self)

        self.ui.start_thread_button.clicked.connect(self._run_thread_function)

        self._thread = threading.Thread(target=self._run_thread_callback)
        self._thread.daemon = True
        self._thread.start()

        self.ui.show()

    def _run_thread_callback(self):
        while True:
            if self._run_thread:
                print("running thread code...")
                time.sleep(10)
                print("thread code finished")
                self._run_thread = False

    def _run_thread_function(self):
        print("starting thread...")
        self._run_thread = True


def main():
    app = QtWidgets.QApplication(sys.argv)
    MyApp()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

1 个答案:

答案 0 :(得分:1)

下面是一个简单的演示,展示了如何启动和停止工作线程,以及使用gui线程安全地进行comminucate。

import sys
from PyQt5 import QtCore, QtWidgets

class Worker(QtCore.QThread):
    dataSent = QtCore.pyqtSignal(dict)

    def __init__(self, parent=None):
        super(Worker, self).__init__(parent)
        self._stopped = True
        self._mutex = QtCore.QMutex()

    def stop(self):
        self._mutex.lock()
        self._stopped = True
        self._mutex.unlock()

    def run(self):
        self._stopped = False
        for count in range(10):
            if self._stopped:
                break
            self.sleep(1)
            data = {
                'message':'running %d [%d]' % (
                    count, QtCore.QThread.currentThreadId()),
                'time': QtCore.QTime.currentTime(),
                'items': [1, 2, 3],
                }
            self.dataSent.emit(data)

class Window(QtWidgets.QWidget):
    def __init__(self):
        super(Window, self).__init__()
        self.edit = QtWidgets.QPlainTextEdit()
        self.edit.setReadOnly(True)
        self.button = QtWidgets.QPushButton('Start')
        self.button.clicked.connect(self.handleButton)
        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.edit)
        layout.addWidget(self.button)
        self._worker = Worker()
        self._worker.started.connect(self.handleThreadStarted)
        self._worker.finished.connect(self.handleThreadFinished)
        self._worker.dataSent.connect(self.handleDataSent)

    def handleThreadStarted(self):
        self.edit.clear()
        self.button.setText('Stop')
        self.edit.appendPlainText('started')

    def handleThreadFinished(self):
        self.button.setText('Start')
        self.edit.appendPlainText('stopped')

    def handleDataSent(self, data):
        self.edit.appendPlainText('message [%d]' %
            QtCore.QThread.currentThreadId())
        self.edit.appendPlainText(data['message'])
        self.edit.appendPlainText(data['time'].toString())
        self.edit.appendPlainText(repr(data['items']))

    def handleButton(self):
        if self._worker.isRunning():
            self._worker.stop()
        else:
            self._worker.start()

if __name__ == '__main__':

    app = QtWidgets.QApplication(sys.argv)
    window = Window()
    window.setGeometry(500, 100, 400, 400)
    window.show()
    sys.exit(app.exec_())