Qt for Python (PySide2) の基本的な使い方
[履歴] [最終更新] (2018/07/17 01:36:15)
1
作品
410
技術情報
最近の投稿
ここは
趣味の電子工作を楽しむ人のためのハードウェア情報共有サイト

技術情報や作品の投稿機能、リアルタイム遠隔操作 API をご利用いただけます。
新着作品

概要

QT を Python から利用するためのライブラリには PyQt や PySide 等が存在します。PySide は元々 QT4 向けのライブラリでしたが、QT5 に対応するために新たに PySide2 が開発されました。PySide2 は Qt for Python ともよばれています。

Q: PySide? Qt for Python? what is the name?
A: The name of the project is Qt for Python and the name of the module is PySide2.
Q: Why PySide2 and not just PySide?
A: Since PySide was developed for Qt4, when the port was made to support Qt5, the name was changed to PySide2 to infer that is was a newer version.
https://wiki.qt.io/Qt_for_Python

PySide2 について基本的な使い方を記載します。今回は VirtualBox と Vagrant で Debian9/stretch をインストールして利用することにします。

以下のコマンドで同期しつつ、X11 で動作確認します。

vagrant rsync
vagrant rsync-auto

インストール

必要なバージョンの python や qt5 等をインストールする必要があります。

python

pyenv を利用すると簡単です。今回は 2.7.15 を利用することにします。

pyenv global 2.7.15

PySide2 自体は pip でインストールできます

pip install --index-url=http://download.qt.io/snapshots/ci/pyside/5.9/latest/ pyside2 --trusted-host download.qt.io

qt5 および依存ライブラリ

OpenGL 等が依存先としてまとめてインストールされます。環境によっては pyside2/wiki/Dependencies を参照して、不足しているパッケージを適宜追加でインストールします。

sudo apt-get install qt5-default
sudo apt-get install qttools5-dev-tools

動作検証

DISPLAY が利用できない場合は仮想ディスプレイを作成して利用します。

sample.py

#!/usr/bin/python
# -*- coding: utf-8 -*-

from sys import exit, argv
from PySide2.QtWidgets import QApplication, QLabel

def Main():
    app = QApplication(argv)
    label = QLabel("Hello World")
    label.show()
    exit(app.exec_())

if __name__ == '__main__':
    Main()

Uploaded Image

古い環境の場合は必要な共有ライブラリが存在せずにエラーになります。新しい OS を利用するか、必要に応じてソースコードからビルドします。例えば以下のような libc のバージョンエラーが発生します。

$ python sample.py
Traceback (most recent call last):
  File "sample.py", line 2, in <module>
    from PySide2.QtWidgets import QApplication, QLabel
ImportError: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by /home/username/.pyenv/versions/2.7.15/lib/python2.7/site-packages/PySide2/QtWidgets.so)

以下のようにソースコードからビルドして対応できます。

mkdir glibc_install
cd glibc_install/
wget http://ftp.gnu.org/gnu/glibc/glibc-2.14.1.tar.gz
tar zxvf glibc-2.14.1.tar.gz
cd glibc-2.14.1/
mkdir build
cd build/
../configure --prefix=/opt/glibc-2.14
make -j4
sudo make install
export LD_LIBRARY_PATH=/opt/glibc-2.14/lib

その他の検証用のコード

HTML の利用

#!/usr/bin/python
# -*- coding: utf-8 -*-

from sys import exit, argv
from PySide2.QtWidgets import QApplication, QLabel

def Main():
    app = QApplication(argv)
    label = QLabel("<font color=red size=40>Hello World!</font>")
    label.show()
    exit(app.exec_())

if __name__ == '__main__':
    Main()

Uploaded Image

QML の利用

#!/usr/bin/python
# -*- coding: utf-8 -*-

from sys import exit, argv
from PySide2.QtWidgets import QApplication
from PySide2.QtQuick import QQuickView
from PySide2.QtCore import QUrl

def Main():
    app = QApplication(argv)
    view = QQuickView()
    url = QUrl("view.qml")
    view.setSource(url)
    view.show()
    exit(app.exec_())

if __name__ == '__main__':
    Main()

view.qml

import QtQuick 2.0

Rectangle {
  width: 200
  height: 200
  color: "green"
  Text {
    text: "Hello World"
    anchors.centerIn: parent
  }
}

Uploaded Image

メッセージボックスの利用

#!/usr/bin/python
# -*- coding: utf-8 -*-

from sys import exit, argv
from PySide2.QtWidgets import QApplication, QMessageBox

def Main():
    app = QApplication(argv)
    msg_box = QMessageBox()
    msg_box.setText("Hello World!")
    msg_box.show()
    exit(app.exec_())

if __name__ == '__main__':
    Main()

Uploaded Image

関数を実行する push ボタンの利用

#!/usr/bin/python
# -*- coding: utf-8 -*-

from sys import exit, argv
from PySide2.QtWidgets import QApplication, QPushButton

def f():
    print("clicked!")

def Main():
    app = QApplication(argv)

    # push 時に関数を実行
    button = QPushButton("Click me")
    button.clicked.connect(f)

    buttonExit = QPushButton("Exit")
    buttonExit.clicked.connect(app.exit)

    button.show()
    buttonExit.show()
    exit(app.exec_())

if __name__ == '__main__':
    Main()

Uploaded Image

QWidget を継承したクラスを作成

#!/usr/bin/python
# -*- coding: utf-8 -*-

from sys import exit, argv
from random import choice
from PySide2.QtCore import Qt
from PySide2.QtWidgets import QWidget, QLabel, QPushButton, QVBoxLayout, QApplication

class MyWidget(QWidget):
    def __init__(self):
        super(MyWidget, self).__init__()

        self.nums = ["1", "2", "3"]

        # ラベルの作成
        self.text = QLabel("0")
        self.text.setAlignment(Qt.AlignCenter)

        # push ボタンの作成
        self.button = QPushButton("Click me!")
        self.button.clicked.connect(self.f)

        # ラベルとボタンを格納する箱となるレイアウトの作成
        self.layout = QVBoxLayout()
        self.layout.addWidget(self.text)
        self.layout.addWidget(self.button)
        self.setLayout(self.layout)

    def f(self):
        self.text.setText(choice(self.nums))

def Main():
    app = QApplication(argv)
    widget = MyWidget()
    widget.show()
    exit(app.exec_())

if __name__ == '__main__':
    Main()

Uploaded Image

QDialog を継承したクラスを作成

QDialogQWidget を継承しています。

#!/usr/bin/python
# -*- coding: utf-8 -*-

from sys import exit, argv
from PySide2.QtWidgets import QLineEdit, QPushButton, QApplication, QVBoxLayout, QDialog

class MyForm(QDialog):
    def __init__(self):
        super(MyForm, self).__init__()
        self.setWindowTitle("My Form")

        # 入力フォーム、ボタン
        self.edit = QLineEdit("xxxx")
        self.button = QPushButton("yyyy")
        self.button.clicked.connect(self.f)

        # レイアウト
        layout = QVBoxLayout()
        layout.addWidget(self.edit)
        layout.addWidget(self.button)
        self.setLayout(layout)

    def f(self):
        print ("Hello %s" % self.edit.text())

def Main():
    app = QApplication(argv)
    form = MyForm()
    form.show()
    exit(app.exec_())

if __name__ == '__main__':
    Main()

Uploaded Image

シグナルとスロット

コールバックの代替としてシグナルとスロットが利用できます。QPushButton も内部的にはシグナルとスロットを利用しています。

sample.py

#!/usr/bin/python
# -*- coding: utf-8 -*-

from PySide2.QtCore import QObject, Signal, Slot
from time import sleep

class MyQObject(QObject): # QObject を継承すること
    clicked = Signal()
    changed = Signal(int)

    def __init__(self):
        super(MyQObject, self).__init__()
        self.clicked.connect(self.onClicked)
        self.changed.connect(self.onChanged)

    @Slot()
    def onClicked(self):
        print("clicked")

    @Slot(int)
    def onChanged(self, num):
        print("changed: %d" % num)

    def f(self):
        self.clicked.emit()
        self.changed.emit(123)

def Main():
    obj = MyQObject()

    while True:
        obj.f()
        sleep(1.0)

if __name__ == '__main__':
    Main()

実行例

$ python sample.py
clicked
changed: 123
clicked
changed: 123
...

プロパティ

Property() を利用すると、Qt オブジェクトと Python オブジェクトのプロパティをバインディングできます。

sample.py

#!/usr/bin/python
# -*- coding: utf-8 -*-

from sys import exit, argv
from PySide2.QtCore import Property
from PySide2.QtWidgets import QWidget, QLabel, QVBoxLayout, QApplication

class MyWidget(QWidget):

    def __init__(self):
        super(MyWidget, self).__init__()
        self.label = QLabel("xxxx")
        self.layout = QVBoxLayout()
        self.layout.addWidget(self.label)
        self.setLayout(self.layout)

    def GetLabelText(self):
        return self.label.text()

    def SetLabelText(self, text):
        self.label.setText(text)

    labelText = Property(str, GetLabelText, SetLabelText)

def Main():
    app = QApplication(argv)
    widget = MyWidget()
    widget.show()

    print(widget.labelText)
    widget.labelText = "yyyy"

    exit(app.exec_())

if __name__ == '__main__':
    Main()

QLabel の初期値が widget.labelText で取得できています。逆に widget.labelText に値を設定すると QLabel に反映されます。

$ python sample.py
xxxx

Uploaded Image

バージョン情報の確認

ipython 等で以下のコマンドを実行して PySide および Qt のバージョンを確認できます。

PySide バージョン

import PySide2.QtCore
print(PySide2.__version__)
→ e.g. 2.0.0

PySide をコンパイルした Qt バージョン

print(PySide2.QtCore.__version__)
→ e.g. 5.11.0

実行時に利用されている Qt バージョン

print(PySide2.QtCore.qVersion())
→ e.g. 5.11.0

都度参照するためのドキュメント

関連ページ
    概要 Qt Quick は、こちらのページで記載した Qt フレームワークにおいて UI 作成のために利用されるライブラリです。Qt Quick で利用される言語 QML (Qt Modeling Language) について、基本的な使い方を記載します。 検証用のコード sample.py #!/usr/bin/python # -*- coding: utf-8 -*- from s
    概要 ロボットアプリケーションの開発環境の一つ OpenRAVE (Open Robotics Automation Virtual Environment) の環境を構築するための手順を記載します。ここでは特に Debian9 を利用します。 インストール 依存パッケージ ビルドツール関連 sudo apt install git build-essential cmake
    概要 リモートホストの X Window System (X11) を転送して利用する方法を、SSH および Virtual Network Computing (VNC) の二つの方法について記載します。 SSH サーバとホストの両方で X11 転送を有効にすることで利用できます。アプリケーション毎に転送できます。
    概要 ロボットシステム開発のためのフレームワーク Robot Operating System (ROS) の環境構築および簡単な使い方について記載します。ここでは Debian9 を利用することにします。ROS は現行バージョン1 の Melodic Morenia ディストリビューションを扱います。 ROS 対応のロボット