PyQt事件循环和ipython

时间:2016-11-15 11:23:00

标签: python qt ipython pyqt4 qtconsole

我有一个显示一些小部件和按钮的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的内部机器之间似乎存在一个阴谋,使得这一切变得不可能:

这是一个长期困扰我的问题。有没有人有解决方案?

1 个答案:

答案 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,具体取决于触发异常的小部件。