这似乎是一个反复出现的问题,但我无法使解决方案始终有效。
我已经尝试过实现这一点,它确实有效,但并不一致。
以下是重现错误的示例代码(单击break按钮可导致崩溃(
此代码由于未保存线程引用而中断(它不会在break_thread()
方法的范围之外持续存在(。因此,它不会到达异常raise RuntimeError("broken")
,因为Qt在之前崩溃
import sys
import time
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QApplication, QPushButton
from PyQt5.QtCore import QThread
def except_hook(cls, exception, error_traceback):
sys.__excepthook__(cls, exception, error_traceback)
class MadeToFail(QThread):
def __init__(self):
super(MadeToFail, self).__init__()
def run(self):
time.sleep(1)
print("finished sleep, about to crash")
raise RuntimeError("broken")
class Window(QtWidgets.QMainWindow):
def break_thread(self):
print("I have been clicked")
try:
thread = MadeToFail()
thread.start()
except Exception as e:
print("caught in class")
print(e)
def __init__(self):
super(Window, self).__init__()
self.setWindowTitle('PyQt5 App')
self.setGeometry(100, 100, 280, 80)
self.move(60, 15)
break_button = QPushButton(parent=self)
break_button.setText("break")
break_button.clicked.connect(self.break_thread)
self.show()
try:
sys.excepthook = except_hook
app = QApplication(sys.argv)
window = Window()
app.exec_()
except Exception as e:
print("caught in program")
print("this should print if the exception is caught")
问题似乎是Qt在内部崩溃,但在某种程度上导致应用程序突然结束,也绕过了我在Exception
上的try/except。这使我无法在崩溃后运行任何类型的代码。
Qt还显示了它自己的错误消息(在这种情况下为QThread: Destroyed while thread is still running
(,但仅此而已,sys.excepthook = except_hook
似乎无法给我完整的错误。
在这种情况下,我只有一个线程,很容易找到原因,但如果代码更大,诊断起来就不那么简单了。
以下是我的问题:
- 如何以Python通常提供的可靠方式获取错误消息
- 如何捕捉Qt错误?或者至少在Qt崩溃后,我如何才能执行一些代码
线程的执行不是同步的,但start((方法表示当事件循环将启动线程的执行时,这就是为什么Qt不使用异常(除了节省内存之外(,因为它们只在同步任务中才有意义。相反,Qt使用两种方法来指示某个东西失败了:如果函数是同步的,那么它返回的是一个状态值;如果它是异步的,那么使用一个信号。
import sys
import time
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton
from PyQt5.QtCore import pyqtSignal, QThread
def some_function():
time.sleep(1)
print("finished sleep, about to crash")
raise RuntimeError("broken")
class MadeToFail(QThread):
error_ocurred = pyqtSignal(Exception, name="errorOcurred")
def run(self):
try:
some_function()
except Exception as e:
self.error_ocurred.emit(e)
class Window(QMainWindow):
def __init__(self):
super(Window, self).__init__()
self.setWindowTitle("PyQt5 App")
self.setGeometry(100, 100, 280, 80)
self.move(60, 15)
break_button = QPushButton(parent=self)
break_button.setText("break")
break_button.clicked.connect(self.break_thread)
def break_thread(self):
test_thread = MadeToFail(self)
test_thread.error_ocurred.connect(self.handle_error_ocurred)
test_thread.start()
def handle_error_ocurred(self, exception):
print(exception)
def main():
app = QApplication(sys.argv)
window = Window()
window.show()
app.exec_()
main()