PyQt5 利用ノート

本稿は PyQt の現時点での最新版、PyQt5 についての覚え書きである。

Note

本稿執筆時の動作環境は次のとおり。

  • OS
    • Windows 7 Home Premium x64 SP1
    • Windows 10 Home x64
  • Python
    • 3.4.1 (x64)
    • 3.5.2 (x64)
  • PyQt
    • GPL v5.4.1 for Python v3.4 (x64)
    • 5.5.1 (mmcauliffe)

関連リンク

PyQt
PyQt 紹介ページ。リリースニュース、ダウンロード、ドキュメントへの各リンクを提供している。
PyQt Download
自分の環境の Python のバージョンに合ったインストーラーを選択するべし。
Qt Documentation
Qt (C++) のドキュメント。
The PyQt Tutorial
GUI をコーディングで実装するタイプのチュートリアル。最終的にテトリス簡易版を実装する。テトリス実装例は PyQt 配布物の examples 内にもある。

目的

ノートを書いておいてなんだが、今後私が PyQt を本格的に利用することはないと思う。数年前に PyQt に興味を持った理由は、所有していた私の貧弱な PC でも、Python での GUI プログラミングならば難なく実現できると考えたからだった。

現在では最近買い替えた PC の性能が良く、自室からインターネットに接続したことと、ディスク容量が格段に増えたことから、PyQt に頼る必要性がなくなった。むしろ Microsoft Visual Studio 無料版をインストールして C# による GUI プログラミングをするほうが Windows しか使わない私としては自然な選択だ。

それでも Qt/PyQt はクラスライブラリーを見ているとためになることが多い。ドキュメントを参照するためだけにインストールしたとしても、得なのではないかと思う。

インストール

公式サイトが提供するバイナリーパッケージを利用してインストールする方法と、 Miniconda を利用してインストールする方法を記す。前者の方法は Python を標準インストーラーによりインストールした場合に採用し、後者の方法は Miniconda で Python 環境を管理している場合に採用することになるはずだ。

インストーラーによる方法

  1. PyQt Download のページで利用環境に適した Windows 用のインストーラーをダウンロードする。本稿では PyQt5-5.4.1-gpl-Py3.4-Qt5.4.1-x64.exe をインストーラーとしている。
  2. ダウンロード終了後、インストーラーを起動する。
    • 途中の選択肢はほとんどない。Full インストールを選択する程度。
    • 普通はインストールが無事に終了する。

Miniconda による方法

こちらの方法は手動による設定作業を部分的に要するので自信がない。

以下、デフォルト環境に PyQt5 をインストールする手順を記すが、当然ながら PyQt5 動作確認用の環境を conda を用いて作成して、そこで構築してもよい。その場合は以下に示す各種ファイルパス等を適宜読み替えて欲しい。

大まかな手順は次の通りだ。すべてコマンドライン処理になる。

  1. コマンド conda install pyqt5 を実行する。
  2. 環境変数 QT_QPA_PLATFORM_PLUGIN_PATH を設定する。

実行例を示す。言い忘れたが Cygwin bash のセッションだ。

$ conda install -c mmcauliffe pyqt5
Fetching package metadata ...........
Solving package specifications: ..........

Package plan for installation in environment D:\Miniconda3:

The following packages will be downloaded:

    package                    |            build
    ---------------------------|-----------------
    icu-56.1                   |                0        11.1 MB  mmcauliffe
    qt5-5.5.1                  |                0        28.8 MB  mmcauliffe
    pyqt5-5.5.1                |           py35_0         3.9 MB  mmcauliffe
    ------------------------------------------------------------
                                           Total:        43.9 MB

The following NEW packages will be INSTALLED:

    icu:   56.1-0       mmcauliffe
    pyqt5: 5.5.1-py35_0 mmcauliffe
    qt5:   5.5.1-0      mmcauliffe

Proceed ([y]/n)?

Fetching packages ...
icu-56.1-0.tar 100% |###############################| Time: X:XX:XX XXX.XX kB/s
qt5-5.5.1-0.ta 100% |###############################| Time: X:XX:XX XXX.XX kB/s
pyqt5-5.5.1-py 100% |###############################| Time: X:XX:XX XXX.XX kB/s
Extracting packages ...
[      COMPLETE      ]|##################################################| 100%
Linking packages ...
INFO:progress.update:('pyqt5', 2)#######################                 |  66%
[      COMPLETE      ]|##################################################| 100%
INFO:progress.stop:None

$ export QT_QPA_PLATFORM_PLUGIN_PATH='D:/Miniconda3/Library/lib/qt5/plugins/platforms/'
  • conda のオプション引数に -c を追加して、パッケージをダウンロードする channel を明示的に指定する必要があった。いずれ標準のパッケージサイトから入手可能になれば、これは不要になると思われる。
  • 最後は bash の組み込みコマンドで環境変数を set しているが、恒久的に指定してよいのであれば、セッション外で定義する。例えば Windows の環境変数を追加するようなやり方で定義する。 PyQt5 稼働テスト用環境とスイッチしながら作業する前提ならば、何か手軽に当該環境変数を set/unset するツールを自作しておくべきだろう。

Note

Miniconda の基本利用法については Miniconda 利用ノート 参照。

Note

PyQt4 との共存については調査中。特に Matplotlib のバックエンド関連での挙動に興味がある。

動作確認

Warning

本節の内容はインストーラーで PyQt5 をインストールした場合を前提とする。

Windows のスタートメニューから適当に辿っていくと PyQt GPL v5.4.1 for Python v3.4 (x64) のような項目ができている。

まずは Examples > PyQt Examples を選択するとよい。 PyQt で実装された様々なデモアプリのランチャーが出現する。画面左のリストから何か興味のあるものを選択して、画面下の Launch ボタンを押すと、デモが開始する。

  • OpenGL のデモが 2D のもの以外動かない。画面が真っ黒か、描画イベントが来ないか。

    PyQt OpenGL Examples

ドキュメント

Warning

本節の内容はインストーラーで PyQt5 をインストールした場合を前提とする。

前述のスタートメニューの Documentation > Qt Documentation を選択すると、 オンラインヘルプ がブラウザーで読める。

PyQt を利用したプログラムを作成する

Warning

本節の内容はインストーラーで PyQt5 をインストールした場合を前提とする。

  • Qt Desinger は GUI を XML ファイルとして記述、保存するためのツール。
    • PyQt4 のときと同じように使える。
  • 記述ファイルの拡張子は .ui となる。
  • Qt Desinger 付属のバッチファイル pyuic5.bat は ui ファイルから py コードを生成するものだ。
  • Python コードから ui ファイルに定義されている GUI を利用することができる。方法は二系統あり、ui ファイルを直接ロードするものと、バッチで生成した py モジュールのクラスをインスタンス化する方法にわかれる。

まずは Qt Designer の利用方法を習得する。目標は次の方法を習得することとしよう。

  • ui ファイルを保存する方法。
  • ui ファイルから py ファイルを生成する方法。
  • ui ファイルで定義した Widget を自作プログラムが利用する方法。

Qt Desinger

前述スタートメニューの Designer を選択する。

  • Designer は GUI を設計するためのツール。設計内容は拡張子 ui のファイルに「上書き保存」または「名前を付けて保存」する。

  • 新規 widget を作成すると、真っ白なウィンドウを画面中央に出す。あとは一般的な RAD ツールと同じように、子 widget をゴテゴテ盛っていく。

    • 各 widget 要素の変数名等のプロパティを変更するには、画面右のオブジェクトインスペクタやプロパティエディタを利用する。
  • 「フォーム>プレビュー」のショートカットキーは Ctrl + R のようだ。

  • 「フォーム>コードを表示」メニュー項目は使いものにならない。 PyQt4 からこの不具合が解消されていないとは?手動で ui ファイルから py ファイルを生成するしかない。

    Qt Designer

    PyQt5 インストールフォルダーにある pyuic5.bat をパスの通ったフォルダーにコピーして、コンソールから同バッチを実行する。コマンドライン引数は Designer で保存した ui ファイル一丁。

    $ pyuic5.bat myform.ui > ui_myform.py
    
  • 一番親の widget にレイアウトを設定するにはコツが要る。ある程度子 widget を親 widget に搭載したら、親で右クリックメニュー表示。「レイアウト」のサブメニューに色々あるので、所望の配置スタイルを選択する。

  • シグナル/スロットの編集はかなり直感的に設定できる。

    • F4 キーでシグナル/スロット編集モードに移行。 connect 関係を定義したい widget 間をドラッグアンドドロップ。ドロップ直後にわかりやすい入力フォームが現れるので、そこで指示。
    • なお F3 キーで GUI 編集モードに移行。

以降の説明では、各ファイル名を次のように決めたものとする。

ファイルの名前 ファイルの意味
myform.ui Qt Designer での GUI 設計内容を保存した XML ファイル。
ui_myform.py 上記 ui ファイルを pyuic5.bat でコンバートした内容を保存したもの。
myapp.py 設計した GUI を利用する Python スクリプトファイル。

ui ファイルから生成した py ファイルの利用法

ファイル ui_myform.py をそのまま実行しても、 Qt Designer で設計した Widget が出てくるわけではない。別のコード(ここでは myapp.py としている)から import して利用する。

色々な流儀があるので、以下に記す。

myform.Ui_Form インスタンスを作成する方法

#!/usr/bin/env pythonw
# -*- coding: utf-8 -*-
"""myapp1.pyw: Create an instance of Ui_Form.
"""
# pylint: disable=no-name-in-module
import sys
from PyQt5.QtWidgets import (QApplication, QWidget)

# pyuic5.bat myform.ui > ui_myform.py
from ui_myform import Ui_Form

def main():
    """Main loop."""

    app = QApplication(sys.argv)
    window = QWidget()
    ui = Ui_Form()
    ui.setupUi(window)

    window.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

QWidget のサブクラスで UI_Form.setupUI を利用する方法

class Form(QWidget):
    """The second example shows the single inheritance approach where we
    sub-class QWidget and set up the user interface in the __init__() method.
    """

    def __init__(self):
        super(Form, self).__init__()

        # Set up the user interface from Designer.
        self.ui = Ui_Form()
        self.ui.setupUi(self)

        # Connect up the buttons.
        self.ui.pushButton.clicked.connect(self.accept)

    def accept(self):
        """NOP"""
        pass

def main():
    """Main loop."""

    app = QApplication(sys.argv)
    window = Form()
    window.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

インポートは先程と同様。

QWidgetUi_Form のサブクラスで setupUI を利用する方法

    def __init__(self):
        super(Form, self).__init__()
        self.setupUi(self)
        self.pushButton.clicked.connect(self.accept)

インポートと main は先程と同様。

ui ファイルから直接 Widget をロードする方法

関数 uic.loadUI を利用する。

#!/usr/bin/env pythonw
# -*- coding: utf-8 -*-
"""myapp4.pyw: Directly load Widget from myform.ui.
"""
# pylint: disable=no-name-in-module
import sys
from os.path import (dirname, join)
from PyQt5 import uic
from PyQt5.QtWidgets import QApplication

def main():
    """Directly load Widget from myform.ui."""

    app = QApplication(sys.argv)
    window = uic.loadUi(join(dirname(__file__), 'myform.ui'))
    window.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

サブクラスに差し替える方法

例えば QTextBrowser を自分でこれから作成する予定のサブクラス QMyTextBrowser に差し替えたい場合は次の手順をとる。

  1. デザイナー画面の QTextBrowser アイテム上で右クリックメニューを表示し、 格上げ先を指定... を選択する。

  2. 入力フォームが出現する。下部にある 格上げされたクラス名QMyTextBrowser と入力する。

  3. 追加 を押す。

  4. 格上げ を押す。

  5. デザイナーで ui ファイルを保存する。

  6. pyuic5.bat で ui ファイルから py ファイルを生成すると、ファイルの下の方に import qmytextbrowser という行が入っているハズ。

  7. qmytextbrowser.py ファイルを作成し、自分でクラスを実装すればよい。

    from PyQt5 import QtWidgets
    
    class QMyTextBrowser(QtWidgets.QTextBrowser):
        ...