LoginSignup
2
0

More than 1 year has passed since last update.

JupyterからQtアプリケーションを動かす

Posted at

はじめに

Jupyter NotebookやJupyter QtConsoleでQtのQWidgetQMainwindowなどをshow()で動かそうとするとイベントループの関係でフリーズするか"Kernel died"になります。マジックコマンド%gui qtでこれは解決しますが、毎回これを実行するのもだるいし、同じコードブロックで実行すると意味がないとか結構謎な挙動を示します。

ここでは、%gui qtの実行を、Qtウィジェットの__init__内で勝手にやってくれる便利な方法を紹介します。

ポイント

  • QWidget.__init__の前にQApplicationを走らせる。
  • QApplicationを走らせる前に%gui qtを走らせる。
  • Garbage collectionでQApplicationが持っていかれないようにする。

方法

まずは%gui qtを走らせてからQApplicationを立ち上げる関数です。

from qtpy.QtWidgets import QApplication

APPLICATION = None

def gui_qt():
    try:
        from IPython import get_ipython
    except ImportError:
        get_ipython = lambda: False

    shell = get_ipython()

    if shell and shell.active_eventloop != "qt":
        shell.enable_gui("qt")
    return None

def get_app():
    gui_qt()
    app = QApplication.instance()
    if app is None:
        app = QApplication([])
    global APPLICATION
    APPLICATION = app
    return app

関数gui_qt内でipythonのシェルを取得し、enable_gui%gui qtを実行します。Jupyter以外の環境でも問題ないように、try/exceptや場合分けを慎重に行います。

関数get_appでは、gui_qtを呼んでからQApplicationを走らせます。すでに走っている場合、クラスメソッドQApplication.instanceQApplicationのインスタンスが取得できるので、これがNoneの場合のみQApplication([])で新しく用意します。

最後に、グローバル変数APPLICATIONに残しておくことで、garbage collectionを回避します。


このget_app関数をコンストラクタ内で実行します。ここでまた、app = get_app()のようにQApplicationインスタンスを取っておかないとなぜかフリーズします。

from qtpy.QtWidgets import QMainWindow

class MyWidget(QMainWindow):
    def __init__(self):
        app = get_app()
        super().__init__()

以上で問題なく起動します。例えばmywidgetモジュールにこれがあれば

from mywidget import MyWidget

widget = MyWidget()
widget.show()

だけでOKです。起動したアプリケーションとJupyterが同時に動かせます。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0