Python GUI 中的 QThread

Python QThread in GUI

我正在尝试按照 this guide 的方法在单独的线程中使用长 运行ning 方法 运行。该功能正在运行,但它仍然导致 GUI 在方法 运行ning 时冻结。我是否遗漏了一些可以让这个 运行 在单独的线程中的东西?

from PySide2.QtWidgets import QDialog, QApplication, QMainWindow
from PySide2.QtCore import Qt, QThread, SIGNAL
import time

class MyClient():
    '''Members of this class get passed to the QThread subclass instance in order to "doSomething" in a separate thread'''
    def __init__(self, name):
        self.name = name

    def doSomething(self):
        time.sleep(10) # but really do something more useful
        return self.name

class WorkerThread(QThread):
    '''Supposed to perform operation in a separate thread so GUI remains responsive.'''

    def __init__(self, client):
        super().__init__()
        self.client = client

    def __del__(self):
        self.wait()

    def run(self):
        print("Running!!!")
        return self.client.doSomething()

class MyForm(QMainWindow):
    def __init__(self, clients):
        super().__init__()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.clients = clients

        # Connect button to method
        self.ui.btn_fetch.clicked.connect(self.fetch)

        self.show()
        self.fetch()

    def printName(self, name):
        print(name)

    def fetch(self):
        for client in self.clients:
            self.workerThread = WorkerThread(client)

            self.connect(self.workerThread, SIGNAL("printName(QString)"), self.printName)

            print("Starting thread")
            self.workerThread.start()
            # GUI becomes unresponsive here until the workerThread finishes.
            print("Thread started")

if __name__ == "__main__":

    clients = [MyClient('foo'), MyClient('bar'), MyClient('baz')]

    app = QApplication(sys.argv)
    w = MyForm(clients)
    w.show()
    sys.exit(app.exec_())

这是一个使用 PyQt5 / PySide2 信号的工作示例:

import sys
import time

from PyQt5.QtWidgets import QDialog, QApplication, QMainWindow
from PyQt5.QtCore import Qt, QThread, QObject, pyqtSignal

# If you need Pyside2 like in your example (untested):
# from PySide2.QtWidgets import QDialog, QApplication, QMainWindow
# from PySide2.QtCore import Qt, QThread, QObject, Signal


class MyClient:
    """Members of this class get passed to the QThread subclass instance
    in order to "doSomething" in a separate thread"""
    def __init__(self, name):
        self.name = name

    def doSomething(self):
        time.sleep(10)  # but really do something more useful
        return self.name


class WorkerThread(QThread):
    didSomething = pyqtSignal(str)

    """Supposed to perform operation in a separate thread so GUI remains responsive."""
    def __init__(self, client):
        super().__init__()
        self.client = client

    def run(self):
        print("Running!!!")
        self.didSomething.emit(self.client.doSomething())


class MyForm(QMainWindow):
    def __init__(self, clients):
        super().__init__()
        self.clients = clients

        # self.ui = Ui_MainWindow()
        # self.ui.setupUi(self)

        # Connect button to method
        # self.ui.btn_fetch.clicked.connect(self.fetch)

        self.workerThreads = []

        self.fetch()

    def printName(self, name):
        print(name)

    def removeThread(self, workerThread):
        def removeWorkerThread():
            self.workerThreads.remove(workerThread)
            print('Thread removed. Total active threads: {}'.format(len(self.workerThreads)))
        return removeWorkerThread

    def fetch(self):
        for client in self.clients:
            workerThread = WorkerThread(client)
            workerThread.didSomething.connect(self.printName)
            workerThread.finished.connect(self.removeThread(workerThread))
            self.workerThreads.append(workerThread)

            print("Starting thread")
            workerThread.start()

            # GUI becomes unresponsive here until the workerThread finishes.
            print("Thread started")


if __name__ == "__main__":
    myClients = [MyClient('foo'), MyClient('bar'), MyClient('baz')]

    app = QApplication(sys.argv)
    w = MyForm(myClients)
    w.show()
    sys.exit(app.exec_())