我有一个显示一些小部件和按钮的PyQt程序。
我希望程序既可以作为独立的python实例运行,也可以在ipython环境中运行。在这种情况下,我在Jupyter控制台中使用以下magic命令(以前我必须在启动ipython qtconsole时使用--gui = qt)
%pylab qt
为了让程序双向工作,我的主模块有以下几行:
APP = QtGui.Qapplication.instance() # retrieves the ipython qt application if any
if APP is None:
APP = QtGui.QApplication(["foo"]) # create one if standalone execution
if __name__=='__main__':
APP.exec_() # Launch the event loop here in standalone mode
这是我的问题:事件循环生成的异常很难被用户检测到,因为它们会在后台控制台弹出。我想捕获事件循环中发生的任何异常,并显示警告(对于QMainWindow状态栏中的intance,以使用户意识到发生了异常)。
我尝试了几种策略,但是PyQt和Ipython的内部机器之间似乎存在一个阴谋,使得这一切变得不可能:
这是一个长期困扰我的问题。有没有人有解决方案?
答案 0 :(得分:4)
实际上,开发人员的回答指出了我正确的方向: 问题是每次执行一个ipython单元时,都会对一个新的sys.excepthook进行monkeypatched,一旦执行完毕,sys.excepthook就会被带回到前一个(参见ipkernel / kernelapp.py)。
因此,在正常的ipython单元指令中更改sys.excepthook不会改变在qt事件循环期间执行的异常错误。
一个简单的解决方案是在qt事件中monkeypatch sys.excepthook:
from PyQt4 import QtCore, QtGui
import sys
from traceback import format_exception
def new_except_hook(etype, evalue, tb):
QtGui.QMessageBox.information(None,
str('error'),
''.join(format_exception(etype, evalue, tb)))
def patch_excepthook():
sys.excepthook = new_except_hook
TIMER = QtCore.QTimer()
TIMER.setSingleShot(True)
TIMER.timeout.connect(patch_excepthook)
TIMER.start()
这个方法的一个好处是它适用于独立和ipython执行。
我想也可以想象通过在每个小部件的event_handler中调用patch_excepthook来修补不同版本的new_except_hook,具体取决于触发异常的小部件。