PyQt5 窗口中的多线程

Posted

技术标签:

【中文标题】PyQt5 窗口中的多线程【英文标题】:Multithreading in PyQt5 Window 【发布时间】:2021-06-06 05:56:53 【问题描述】:

我有两个函数(do_work,do_work2)我如何多线程? 如果我使用一个线程它工作正常,如果我尝试添加一个或多个它不会工作。 我想在我的函数中有 while True 循环。 我已经尝试将 self.continue_run 更改为 : self.continue_run2 用于第二个功能,但仍然无法正常工作。

希望有人能帮助我

import sys
from PyQt5.QtWidgets import (QWidget,
                         QPushButton, QApplication, QGridLayout)
from PyQt5.QtCore import QThread, QObject, pyqtSignal
import keyboard
import time

class Worker(QObject):

    finished = pyqtSignal()  # give worker class a finished signal

    def __init__(self, parent=None):
        QObject.__init__(self, parent=parent)
        self.continue_run = True  # provide a bool run condition for the class

    def do_work(self):
        while self.continue_run:  # give the loop a stoppable condition
            print("Thread 1")
        self.finished.emit()  # emit the finished signal when the loop is done

    def do_work2(self):
        while self.continue_run:  # give the loop a stoppable condition
            print("Thread 2")
            
        self.finished.emit()  # emit the finished signal when the loop is done

    def stop(self):
        self.continue_run = False  # set the run condition to false on stop


class Gui(QWidget):

    stop_signal = pyqtSignal()  # make a stop signal to communicate with the worker in another thread

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

    def initUI(self):

        # Buttons:
        self.btn_start = QPushButton('Start')
        self.btn_start.resize(self.btn_start.sizeHint())
        self.btn_start.move(50, 50)
        self.btn_stop = QPushButton('Stop')
        self.btn_stop.resize(self.btn_stop.sizeHint())
        self.btn_stop.move(150, 50)

        # GUI title, size, etc...
        self.setGeometry(300, 300, 300, 220)
        self.setWindowTitle('ThreadTest')
        self.layout = QGridLayout()
        self.layout.addWidget(self.btn_start, 0, 0)
        self.layout.addWidget(self.btn_stop, 0, 50)
        self.setLayout(self.layout)

        # Thread:
        self.thread = QThread()
        self.worker = Worker()
        self.stop_signal.connect(self.worker.stop)  # connect stop signal to worker stop method
        self.worker.moveToThread(self.thread)

        self.worker.finished.connect(self.thread.quit)  # connect the workers finished signal to stop thread
        self.worker.finished.connect(self.worker.deleteLater)  # connect the workers finished signal to clean up worker
        self.thread.finished.connect(self.thread.deleteLater)  # connect threads finished signal to clean up thread

        self.thread.started.connect(self.worker.do_work)
        self.thread.finished.connect(self.worker.stop)

        self.thread.started.connect(self.worker.do_work2)
        self.thread.finished.connect(self.worker.stop)

        # Start Button action:
        self.btn_start.clicked.connect(self.thread.start)

        # Stop Button action:
        self.btn_stop.clicked.connect(self.stop_thread)

        self.show()

    # When stop_btn is clicked this runs. Terminates the worker and the thread.
    def stop_thread(self):
        self.stop_signal.emit()  # emit the finished signal on stop


if __name__ == '__main__':
    app = QApplication(sys.argv)
    gui = Gui()
    sys.exit(app.exec_())

【问题讨论】:

如果你想运行两个无限循环,你需要两个独立的线程和两个工作对象,因为一个工作人员只能是一个线程的一部分。 【参考方案1】:

您的逻辑的两个主要问题之一是您已将finished 信号连接到deleteLeter,结果是第二个函数无论如何都不会运行,因为您删除了两个线程工人。

第一个重要的问题是,将两个函数移动到一个线程不会使它们同时运行:一个线程一次只能做一件事,不管它是否是“主”线程。

当线程启动时,它会启动started 信号连接到的第一个函数,第二个函数只会在第一个函数返回后立即运行(但在你的情况下,如前所述,因为你'重新删除两个对象)。

考虑以下示例:

class WorkerTest(QtCore.QObject):
    def firstFunction(self):
        print('starting first function')
        sleep(2)
        print('finished first function')

    def secondFunction(self):
        print('starting second function')
        sleep(2)
        print('finished second function')


class Test(QtWidgets.QPushButton):
    def __init__(self):
        super().__init__('start')
        self.worker = WorkerTest()
        self.thread = QtCore.QThread()
        self.worker.moveToThread(self.thread)
        self.thread.started.connect(self.worker.firstFunction)
        self.thread.started.connect(self.worker.secondFunction)
        self.clicked.connect(self.thread.start)

如果您运行上面的代码,您会看到第二个函数只有在第一个函数完成后才会运行。

如果你想有两个并发线程,创建两个线程。

如果您想让另一个线程运行(或替代)第一个线程,请将finished 信号连接到一个函数,该函数将started 与第一个函数断开连接并连接到第二个。

【讨论】:

以上是关于PyQt5 窗口中的多线程的主要内容,如果未能解决你的问题,请参考以下文章

java中的多线程

九PyQt5多线程编程

SQLite中的多线程数据写入[重复]

Java中的多线程概念

需要有关 gtkmm 中的多线程的帮助

如何在 PyQt5 中同时读取和写入文件时正确执行多线程?