2016-11-15 24 views
3

我有一个显示一些小部件和按钮的PyQt程序。在PyQt事件循环和ipython的例外

我希望程序既可以作为独立的python实例运行,也可以在ipython环境中运行。在这种情况下,我在Jupyter控制台使用以下命令魔法(以前我不得不使用--gui = QT启动IPython中qtconsole时)

%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状态栏中进行实例,以使用户意识到发生了异常)。

我已经尝试了几种策略,但似乎有PyQt的年代和IPython的内部机器之间的阴谋,使这个不可能的:

这是一个长期以来一直困扰着我的问题。有没有人有办法解决吗?

+0

尝试在[此答案]中建议的解决方案(http://stackoverflow.com/a/28758396/984421)。 – ekhumoro

+0

我忘了这个:覆盖IPython将用作sys的猴子补丁的函数。excepthook(正如您的答案中所建议的)也不起作用。实际上,带有qt选项的Ipython将阻止qt事件循环甚至调用sys.excepthook。我不明白IPython开发人员在捕获事件循环异常时发现如此猥亵?! – Samuel

+0

老实说,我认为这里报告所有这些都是浪费时间:你需要把它与ipython开发者结合起来。 – ekhumoro

回答

4

实际上,开发人员的回答指出我的方向是正确的: 问题在于,每次执行ipython单元时,新的sys.excepthook都会被monkeypatched,一旦执行完成,sys.excepthook被带回到前一个(见ipkernel/kernelapp.py)。

因此,在正常的ipython单元指令中更改sys.excepthook不会更改在qt事件循环期间执行的excepthook。

一个简单的解决方案是猴补丁Qt的事件中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。