PyQt:如何捕捉Qt崩溃并获得可靠的错误消息



这似乎是一个反复出现的问题,但我无法使解决方案始终有效。

我已经尝试过实现这一点,它确实有效,但并不一致。

以下是重现错误的示例代码(单击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()

最新更新