我想在我的应用程序中有2个工作线程。一旦GUI加载就应该开始运行,另一个应该稍后通过一些信号启动。让我们说它是一个按钮点击。
当我的Python解释器在执行第二个线程时崩溃(如显示Windows错误" Python停止工作",没有堆栈跟踪)时,我遇到了一种奇怪的行为。
这是一个例子,在我点击按钮后会立即崩溃。
class Worker(QtCore.QThread):
def __init__(self, method_to_run):
super().__init__()
self.method = method_to_run
def run(self):
self.method()
class Window(QWidget):
def __init__(self):
super(Window, self).__init__()
self.button = QPushButton('Test', self)
self.label = QLabel(self)
self.button.clicked.connect(self.handleButton)
layout = QVBoxLayout(self)
layout.addWidget(self.label)
layout.addWidget(self.button)
self.worker = Worker(self.test_method)
self.worker.start()
def handleButton(self):
self.label.setText('Button Clicked!')
worker = Worker(self.test_method)
worker.start()
@staticmethod
def test_method():
res = [i*i for i in range(100500)]
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
更奇怪的是,当您因某种原因调试应用程序时它不会崩溃。
我在这里缺少什么?
修改 我可以从故障转移中得到很多,因为我没有QT的符号。但看起来崩溃发生在QtCore.dll
中ExceptionAddress: 00000000632d4669 (Qt5Core!QThread::start+0x0000000000000229)
答案 0 :(得分:1)
您点击触发的帖子实际上并未尝试在线程中执行操作。您调用方法,而不是将该方法作为参数传递,因此您尝试使用test_method
(None
)的返回值作为方法运行
变化:
worker = Worker(self.test_method()) # Calls test_method and tries to run None
为:
worker = Worker(self.test_method) # Don't call test_method
答案 1 :(得分:1)
问题是您没有保存对该帖子的引用,所以一旦您退出handleButton
,它就会被删除。如果你保存一个引用,那就引出了如何处理它的生命周期的问题。
QThread
不仅仅是系统线程的包装器 - 它实现了其他服务,可以让您将线程连接到GUI。您可以使用其finished
处理程序在窗口小部件终止时发出任何清理信号。
在此示例中,我将工作程序保存为self.worker2
并阻止第二次启动工作程序,直到完成第一个工作程序。
import PyQt5
import PyQt5.QtCore as QtCore
from PyQt5.QtWidgets import *
import time
class Worker(QtCore.QThread):
def __init__(self, method_to_run):
super(Worker, self).__init__()
self.method = method_to_run
def run(self):
self.method()
class Window(QWidget):
def __init__(self):
super().__init__()
self.button = QPushButton('Test', self)
self.label = QLabel(self)
self.button.clicked.connect(self.handleButton)
layout = QVBoxLayout(self)
layout.addWidget(self.label)
layout.addWidget(self.button)
self.worker = Worker(self.test_method)
self.worker.start()
self.worker2 = None
def handleButton(self):
self.label.setText('Button Clicked!')
# likely better to disable the button instead... but
# this shows events in action.
if self.worker2:
self.label.setText('Worker already running')
else:
self.worker2 = Worker(self.test_method)
self.worker2.finished.connect(self.handle_worker2_done)
self.worker2.start()
def handle_worker2_done(self):
self.worker2 = None
self.label.setText('Worker done')
@staticmethod
def test_method():
#res = [i*i for i in range(100500)]
time.sleep(3)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())