Qt for Pythonで手軽にGUIアプリを作る (導入編)

Qt for Python をPyPIからインストールできるようになったので試してみました。C++で組むときと同様の感覚で手軽にGUIアプリケーションを簡単に組めるようです。
2018.07.27

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

少し前になりますが、 Qt Blog の記事でPyPIからQt for Pythonを利用できるようになったとアナウンスがありました。

今回はQt for Pythonを使ったGUIアプリケーションを試してみます。

検証環境

  • Python: 3.7.0
  • Pipenv: 2018.05.18
  • PySide2: 5.11.0 (Qt for python)

Qtって何?

Qtはクロスプラットフォーム開発のためのフレームワークです。今回はGUIの機能を利用しますが、ネットワークやマルチメディアなど数多くのライブラリが用意されています。 対応しているプラットフォームも多く、デスクトップ・スマートフォン・組み込み機器と多くの環境で利用できるようです。

また、シグナル・スロットと呼ばれる仕組みが用意されていて、簡単に Observer を実装できるようになっています。

今回はシグナル・スロットを使って、ボタンを押したらダイアログを表示するだけの簡単なGUIアプリケーションを作成してみます。

環境構築

Pipenv を使ってQt for Pythonの環境を構築します。

まず、Pipenvの環境を構築します。今回はCPython3.7.0を使います。

$ mkdir qt-for-python
$ cd qt-for-python
$ pipenv install --python 3.7.0
Creating a virtualenv for this project…
Using /Users/yoshihitoh/.pyenv/versions/3.7.0/bin/python3.7m (3.7.0) to create virtualenv…
⠋Running virtualenv with interpreter /Users/yoshihitoh/.pyenv/versions/3.7.0/bin/python3.7m
Using base prefix '/Users/yoshihitoh/.pyenv/versions/3.7.0'
/Users/yoshihitoh/.pyenv/versions/3.6.5/lib/python3.6/site-packages/virtualenv.py:1041: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
  import imp
New python executable in /Users/yoshihitoh/.local/share/virtualenvs/qt-for-python-T_faoBtg/bin/python3.7m
Also creating executable in /Users/yoshihitoh/.local/share/virtualenvs/qt-for-python-T_faoBtg/bin/python
Installing setuptools, pip, wheel...done.

Virtualenv location: /Users/yoshihitoh/.local/share/virtualenvs/qt-for-python-T_faoBtg
Creating a Pipfile for this project…
Pipfile.lock not found, creating…
Locking [dev-packages] dependencies…
Locking [packages] depend encies…
Updated Pipfile.lock (a65489)!
Installing dependencies from Pipfile.lock (a65489)…
    ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 0/0 — 00:00:00
To activate this project's virtualenv, run the following:

上記の手順でPipenvのシェルに切り替わると思いますが、もし変わらない場合は明示的に切り替えましょう。

$ pipenv shell

次に、Qt for Pythonをインストールします。冒頭に書いたとおりPyPIからインストールできるようになったので、コマンド1発でインストールできます。

$ pipenv install pyside2
Installing pyside2…
Collecting pyside2
  Using cached https://files.pythonhosted.org/packages/cf/6b/fd9f375bcbe76df0e85729956c3ce3a299b38efbd9d61c6bd58fe5c9bf9e/PySide2-5.11.0-5.11.0-cp35.cp36-abi3-macosx_10_11_intel.whl
Installing collected packages: pyside2
Successfully installed pyside2-5.11.0

Adding pyside2 to Pipfile's [packages]…
Pipfile.lock (7fafad) out of date, updating to (d69f89)…
Locking [dev-packages] dependencies…
Locking [packages] dependencies…
Updated Pipfile.lock (d69f89)!
Installing dependencies from Pipfile.lock (d69f89)…
    ▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉ 2/2 — 00:00:00

簡単にインストールできましたね!せっかくなのでインストールした内容を確認してみましょう。

$ cd "$VIRTUAL_ENV/lib/python3.7/site-packages/PySide2"
$ ls -la
total 212488
drwxr-xr-x   6 yoshihitoh  staff   204B  7 27 15:34 Qt
-rwxr-xr-x   1 yoshihitoh  staff   333K  7 27 15:34 Qt3DAnimation.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   400K  7 27 15:34 Qt3DCore.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   776K  7 27 15:34 Qt3DExtras.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   411K  7 27 15:34 Qt3DInput.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff    75K  7 27 15:34 Qt3DLogic.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   1.8M  7 27 15:34 Qt3DRender.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   1.4M  7 27 15:34 QtCharts.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff    42K  7 27 15:34 QtConcurrent.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   4.3M  7 27 15:34 QtCore.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   1.1M  7 27 15:34 QtDataVisualization.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   4.9M  7 27 15:34 QtGui.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   522K  7 27 15:34 QtHelp.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   821K  7 27 15:34 QtLocation.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   116K  7 27 15:34 QtMacExtras.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   1.9M  7 27 15:34 QtMultimedia.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   258K  7 27 15:34 QtMultimediaWidgets.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   1.3M  7 27 15:34 QtNetwork.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   473K  7 27 15:34 QtOpenGL.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   416K  7 27 15:34 QtPositioning.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   469K  7 27 15:34 QtPrintSupport.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   527K  7 27 15:34 QtQml.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   867K  7 27 15:34 QtQuick.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   133K  7 27 15:34 QtQuickWidgets.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   253K  7 27 15:34 QtScxml.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   830K  7 27 15:34 QtSensors.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   644K  7 27 15:34 QtSql.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   212K  7 27 15:34 QtSvg.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   157K  7 27 15:34 QtTest.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   132K  7 27 15:34 QtTextToSpeech.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   645K  7 27 15:34 QtUiTools.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff    80K  7 27 15:34 QtWebChannel.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff    41K  7 27 15:34 QtWebEngine.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   145K  7 27 15:34 QtWebEngineCore.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   416K  7 27 15:34 QtWebEngineWidgets.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   143K  7 27 15:34 QtWebSockets.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   9.6M  7 27 15:34 QtWidgets.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   560K  7 27 15:34 QtXml.abi3.so
-rwxr-xr-x   1 yoshihitoh  staff   296K  7 27 15:34 QtXmlPatterns.abi3.so
-rw-r--r--   1 yoshihitoh  staff   1.9K  7 27 15:34 __init__.py
drwxr-xr-x   5 yoshihitoh  staff   170B  7 27 15:34 __pycache__
-rw-r--r--   1 yoshihitoh  staff   707B  7 27 15:34 _config.py
-rw-r--r--   1 yoshihitoh  staff   2.4K  7 27 15:34 _git_pyside_version.py
drwxr-xr-x  24 yoshihitoh  staff   816B  7 27 15:34 examples
drwxr-xr-x   4 yoshihitoh  staff   136B  7 27 15:34 include
-rwxr-xr-x   1 yoshihitoh  staff    64M  7 27 15:34 libclang.dylib
-rwxr-xr-x   1 yoshihitoh  staff   208K  7 27 15:34 libpyside2.abi3.5.11.dylib
-rwxr-xr-x   1 yoshihitoh  staff   199K  7 27 15:34 libshiboken2.abi3.5.11.dylib
-rwxr-xr-x   1 yoshihitoh  staff   212K  7 27 15:34 pyside2-lupdate
-rwxr-xr-x   1 yoshihitoh  staff    72K  7 27 15:34 pyside2-rcc
drwxr-xr-x   5 yoshihitoh  staff   170B  7 27 15:34 scripts
-rwxr-xr-x   1 yoshihitoh  staff   2.0M  7 27 15:34 shiboken2
-rwxr-xr-x   1 yoshihitoh  staff    21K  7 27 15:34 shiboken2.abi3.so
drwxr-xr-x   5 yoshihitoh  staff   170B  7 27 15:34 support
drwxr-xr-x  55 yoshihitoh  staff   1.8K  7 27 15:34 typesystems

Qt*.solibclang.dylib といった依存ライブラリも同梱されているので、別途インストールする必要は無いようです。

試す

プログラム

同梱の examples/ 以下のファイルを参考に実装してみましょう。

main.py

import sys
from PySide2 import QtWidgets


def show_message():
    messagebox = QtWidgets.QMessageBox(QtWidgets.QMessageBox.Information,
                                       'Title - Hello',
                                       'Hello, Qt for Python!',
                                       QtWidgets.QMessageBox.Close
                                       )
    messagebox.exec_()


def main():
    # アプリケーション作成、Qt初期化のために最初にインスタンス化すること
    app = QtWidgets.QApplication(sys.argv)

    # ボタン作成
    button = QtWidgets.QPushButton('click me!')
    button.resize(100, 40)
    button.show()

    # ボタンクリック時のシグナルに、メッセージ表示のスロット(関数)を結びつける
    button.clicked.connect(show_message)

    # アプリケーションを起動する
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

QApplication のインスタンス生成前にボタンやメッセージボックスを作成すると、 QWidget: Must construct a QApplication before a QWidget というエラーが発生するようです。

実行結果

早速実行してみましょう

$ python main.py

GUIが起動しましたね!ボタンをクリックしてみましょう

メッセージボックスも表示されました!シグナル/スロットの接続も問題なさそうですね。

おわりに

今回はQt for Pythonを使って簡単にGUIアプリケーションを組めることを確認できました。

Qtの特徴であるシグナル・スロットはとても便利な機構です。 今回は QPushButton に定義されているシグナルを使ってみましたが、次回は独自のシグナルを実装する例を試してみたいと思います。