我的问题是,我的线程似乎启动得很好,但我没有从它应该执行的函数中得到任何输出,我不明白为什么。
我有一个文件,为了演示的目的,就说它叫 "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_())
任何帮助、解释、建议都非常感激!
你的代码存在多个问题。
首先,你的代码有多个问题。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,请删除它们。