4

いくつかのウィジェットとボタンを表示している PyQt プログラムがあります。

プログラムをスタンドアロンの python インスタンスとして、または ipython 環境内で実行したいと考えています。この場合、Jupyter コンソールで次のマジック コマンドを使用します (以前は、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 ステータス バーに例外が発生したことをユーザーに知らせるため)。

私はいくつかの戦略を試しましたが、これを不可能にするために PyQt と Ipython の内部機構の間に陰謀があるようです:

昔からずっと頭を悩ませている問題です。誰にも解決策がありますか?

4

1 に答える 1

5

実際、開発者の答えは私を正しい方向に向けました: 問題は、ipython セルが実行されるたびに、新しい sys.excepthook がモンキーパッチされ、実行が完了すると、sys.excepthook が以前のものに戻されることです ( ipkernel/kernelapp.py を参照してください)。

このため、通常の ipython cell 命令で sys.excepthook を変更しても、qt イベント ループ中に実行される excepthook は変更されません。

簡単な解決策は、qt イベント内で sys.excepthook を monkeypatch することです。

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 にモンキー パッチを適用することも想像できると思います。

于 2016-11-18T10:06:10.743 に答える