据我所知,如果在PyQt下的插槽中发生异常,该异常会打印到屏幕上,但不会冒泡。这在我的测试策略中造成了一个问题,因为如果插槽中发生异常,我将不会看到测试失败。
这是一个例子:
import sys from PyQt4 import QtGui, QtCore class Test(QtGui.QPushButton): def __init__(self, parent=None): QtGui.QWidget.__init__(self, parent) self.setText("hello") self.connect(self, QtCore.SIGNAL("clicked()"), self.buttonClicked) def buttonClicked(self): print "clicked" raise Exception("wow") app=QtGui.QApplication(sys.argv) t=Test() t.show() try: app.exec_() except: print "exiting"
请注意,异常永远不会退出程序。
有没有解决此问题的方法?
可以创建一个包装PyQt的新信号/插槽装饰器的装饰器,并为所有插槽提供异常处理。也可以重写QApplication :: notify来捕获未捕获的C ++异常。
import sys import traceback import types from functools import wraps from PyQt4 import QtGui, QtCore def MyPyQtSlot(*args): if len(args) == 0 or isinstance(args[0], types.FunctionType): args = [] @QtCore.pyqtSlot(*args) def slotdecorator(func): @wraps(func) def wrapper(*args, **kwargs): try: func(*args) except: print "Uncaught Exception in slot" traceback.print_exc() return wrapper return slotdecorator class Test(QtGui.QPushButton): def __init__(self, parent=None): QtGui.QWidget.__init__(self, parent) self.setText("hello") self.clicked.connect(self.buttonClicked) @MyPyQtSlot("bool") def buttonClicked(self, checked): print "clicked" raise Exception("wow") class MyApp(QtGui.QApplication): def notify(self, obj, event): isex = False try: return QtGui.QApplication.notify(self, obj, event) except Exception: isex = True print "Unexpected Error" print traceback.format_exception(*sys.exc_info()) return False finally: if isex: self.quit() app = MyApp(sys.argv) t=Test() t.show() try: app.exec_() except: print "exiting"