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()
古い環境の場合は必要な共有ライブラリが存在せずにエラーになります。新しい 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()
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
}
}
メッセージボックスの利用
#!/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()
関数を実行する 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()
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()
QDialog を継承したクラスを作成
#!/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()
シグナルとスロット
コールバックの代替としてシグナルとスロットが利用できます。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
バージョン情報の確認
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
都度参照するためのドキュメント
関連記事
- QML の基本的な使い方Qt Quick は、Qt フレームワークにおいて UI 作成のために利用されるライブラリです。Qt Quick で利用される言語 QML (Qt Modeling Language) について、基本的な使い方を記載します。 検証用のコード sample.py #!/usr/bin/python # -*- coding: utf-8 -*- from sys import exit
- Python コードスニペット (条件分岐)if-elif-else sample.py #!/usr/bin/python # -*- coding: utf-8 -*- # コメント内であっても、ASCII外の文字が含まれる場合はエンコーディング情報が必須 x = 1 # 一行スタイル if x==0: print 'a' # 参考: and,or,notが使用可能 (&&,||はエラー) elif x==1: p...
- Python コードスニペット (リスト、タプル、ディクショナリ)リスト range 「0から10まで」といった範囲をリスト形式で生成します。 sample.py print range(10) # for(int i=0; i<10; ++i) ← C言語などのfor文と比較 print range(5,10) # for(int i=5; i<10; ++i) print range(5,10,2) # for(int i=5; i<10;...
- ZeroMQ (zmq) の Python サンプルコードZeroMQ を Python から利用する場合のサンプルコードを記載します。 Fixing the World To fix the world, we needed to do two things. One, to solve the general problem of "how to connect any code to any code, anywhere". Two, to wra...
- Matplotlib/SciPy/pandas/NumPy サンプルコードPython で数学的なことを試すときに利用される Matplotlib/SciPy/pandas/NumPy についてサンプルコードを記載します。 Matplotlib SciPy pandas [NumPy](https://www.numpy