PyQtPySide2与QThread实现的问题,我试图将另一个类的方法传递给线程类的构造函数。

问题描述 投票:0回答:1

我的问题是,我的线程似乎启动得很好,但我没有从它应该执行的函数中得到任何输出,我不明白为什么。

我有一个文件,为了演示的目的,就说它叫 "so_helpers"。里面有2个类,一个是QThread,叫做 "External",我试图以一种智能的方式构造和运行(显然不是,因为它没有工作),另一个是Updater,我试图将其方法传递给External来执行。下面是我的 "so_helpers "的代码。

from PySide2.QtCore import QThread, Signal

class Updater: 
    def __init__(self):
        print("connection to db established")

    def process(self):
        print("started")
        print("doing the update")
        print("finished")

class External(QThread):
    finished = Signal()

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

    def run(self):
        self.func()
        self.finished.emit()

这是我的用户界面, 在这个例子中, 我们称它为 "for_SO_ui". 它是由pyuic5从.ui文件中自动生成的。

from PySide2 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(644, 187)
        MainWindow.setMinimumSize(QtCore.QSize(644, 187))
        MainWindow.setMaximumSize(QtCore.QSize(644, 187))
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(80, 30, 491, 111))
        self.pushButton.setObjectName("pushButton")
        MainWindow.setCentralWidget(self.centralwidget)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.pushButton.setText(_translate("MainWindow", "THREADING IS AWESOME!"))


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

这里是main.py,所有的东西都应该在一起(但它没有,这让我很伤心)。

from so_helpers import *
from for_SO_ui import *
from PySide2 import QtCore, QtGui, QtWidgets
from PySide2.QtCore import QThread, Signal
import sys

class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):

    startThread = Signal()
    threadDone = Signal()

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi(self)
        self.connectSignals()

    def connectSignals(self):
        self.pushButton.clicked.connect(self.onButtonClick)
        self.startThread.connect(self.onThreadStart)
        self.threadDone.connect(self.onThreadDone)

    def onButtonClick(self):
        self.startThread.emit()

    def onThreadStart(self):
        self.thread_object = External(self.threadFunction)
        self.thread = QThread()
        self.thread_object.moveToThread(self.thread)
        self.thread_object.finished.connect(self.onThreadDone)
        self.thread.start()

    def onThreadDone(self):
        self.thread.start()

    def threadFunction(self):
        func = Updater.process
        return func

    def closeEvent(self, event):
        self.thread.quit()

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    ui = MainWindow()
    ui.show()
    sys.exit(app.exec_())

任何帮助、解释、建议都非常感激!

python user-interface pyqt5 qthread pyside2
1个回答
1
投票

你的代码存在多个问题。

首先,你的代码有多个问题。External 已经是一个QThread子类,没有必要再创建一个新的线程来放入它。即使在这种情况下,每当你把一个QObject移动到另一个线程时,你应该把它的 started 线程的信号到实际应该执行的函数(在你的例子中。run).

呼叫 self.func() 运行 process 功能,但 threadFunction 取而代之,这只是返回 Updater.process.

然后,你想访问一个函数,但你返回的是未绑定的类方法 (Updater.process),而不是实例方法,所以调用它将导致异常,因为 process 至少需要一个参数(self). 您可以使用 @staticmethod (并去除 self),或者创建一个类的实例。

最后,QThread已经有一个 finished() 信号,你不应该覆盖它,也不应该使用你自己的信号来重新启动线程:当你发出自己的信号时,线程仍然在运行,结果是它有可能不会被再次启动,这在关于 QThread.start():

[...]如果线程已经在运行,这个函数什么都不做。

所以你要么使用原来的QThread finished 信号,或者你用 QThread.wait() 等到完成后再重新开始。

这是对你的代码可能的修正。

class External(QThread):
    def __init__(self, func):
        super().__init__()
        self.func = func

    def run(self):
        self.func()


class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):

    startThread = pyqtSignal()
    threadDone = pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi(self)
        self.connectSignals()

    def connectSignals(self):
        self.pushButton.clicked.connect(self.onButtonClick)
        self.startThread.connect(self.onThreadStart)
        self.threadDone.connect(self.onThreadDone)

    def onButtonClick(self):
        self.startThread.emit()

    def onThreadStart(self):
        self.thread = External(self.threadFunction())
        self.thread.finished.connect(self.onThreadDone)
        self.thread.start()

    def onThreadDone(self):
        self.thread.start()

    def threadFunction(self):
        self.updater = Updater()
        return self.updater.process

    def closeEvent(self, event):
        self.thread.finished.disconnect(self.onThreadDone)
        self.thread.quit()

PS:为了以后的参考:如果为了更好的理解你的代码而不需要docstringscomments,请删除它们。

© www.soinside.com 2019 - 2024. All rights reserved.