「Qtその他 - PyQt5とPySide2」の版間の差分
(→QtPy) |
細 (文字列「__FORCETOC__」を「{{#seo: |title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki |keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,Podman,電気回路,電子回路,基板,プリント基板 |description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This pag…) |
||
(同じ利用者による、間の5版が非表示) | |||
314行目: | 314行目: | ||
== QtPy == | == QtPy == | ||
QtPyは、PyQtやPySideへの単一のAPIを使用して、ソフトウェアが開発できる抽象化レイヤである。<br> | |||
Qt5(QtGuiモジュールがQtGuiとQtWidgetsに分割されている)を使用して、PyQt5、PyQt4、PySide2、PySideをサポートしている。<br> | |||
<br> | |||
PyQt5、PyQt4、PySide2、PySide向けの標準化されたPySide2のようなAPIが提供されている。<br> | |||
PySide2モジュールやPyQt5モジュールの代わりに、qtpyモジュールからQtモジュールをインポートする。<br> | |||
<br> | |||
QtPyを使用するには、PyQt5、PyQt4、PySide2、PySideをインストールしている必要がある。<br> | |||
これらのライブラリのいずれかが存在する場合、環境変数QT_APIを設定しない時は、標準でPyQt5が使用される。<br> | |||
<br> | |||
環境変数<code>QT_API</code>は、以下の値を取ることができる。<br> | |||
* pyqt5 | |||
*: PyQt5を使用する。 | |||
* pyqtまたはpyqt4 | |||
*: PyQt4を使用する。 | |||
* pyside2 | |||
*: PySide2を使用する。 | |||
* pyside | |||
*: PySideを使用する。 | |||
<br> | |||
QtPyをインストールするには、以下のコマンドを実行する。<br> | |||
pip3 install qtpy | |||
<br> | |||
Qt5以外のもの(PyQt 4やPySide 1等)をターゲットにする場合、[https://github.com/spyder-ide/qtpy QtPyのGitHub]を参照すること。<br> | Qt5以外のもの(PyQt 4やPySide 1等)をターゲットにする場合、[https://github.com/spyder-ide/qtpy QtPyのGitHub]を参照すること。<br> | ||
<br> | <br> | ||
QtPyを使用すると、環境変数<code>QT_API</code>を使用して、ソフトウェアから読み込むAPIを制御できる。<br> | QtPyを使用すると、環境変数<code>QT_API</code>を使用して、ソフトウェアから読み込むAPIを制御できる。<br> | ||
325行目: | 346行目: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<br><br> | <br><br> | ||
== エラー関連 == | |||
PySide2プロジェクトを実行する時、以下のような警告が出力される場合がある。<br> | |||
Qt WebEngine seems to be initialized from a plugin. | |||
Please set Qt::AA_ShareOpenGLContexts using QCoreApplication::setAttribute before constructing QGuiApplication. | |||
<br> | |||
これは、<code>QApplication</code>クラスのインスタンスを生成する前に、<code>AA_ShareOpenGLContexts</code>を設定することで修正できる。<br> | |||
以下の例は、PySide2を使用している場合である。<br> | |||
<syntaxhighlight lang="python"> | |||
from PySide2 import QtCore, QtWidgets | |||
# ...略 | |||
if __name__ == '__main__': | |||
QCoreApplication.setAttribute(Qt.AA_ShareOpenGLContexts) | |||
app = QApplication(sys.argv) | |||
# ...略 | |||
</syntaxhighlight> | |||
<br> | |||
また、PySide6を使用することで警告を回避することもできる。<br> | |||
<br><br> | |||
{{#seo: | |||
|title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki | |||
|keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,Podman,電気回路,電子回路,基板,プリント基板 | |||
|description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This page is {{PAGENAME}} in our wiki about electronic circuits and SUSE Linux | |||
|image=/resources/assets/MochiuLogo_Single_Blue.png | |||
}} | |||
__FORCETOC__ | |||
[[カテゴリ:Qt]][[カテゴリ:Python]] | |||
{{#seo: | |||
|title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki | |||
|keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,Podman,電気回路,電子回路,基板,プリント基板 | |||
|description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This page is {{PAGENAME}} in our wiki about electronic circuits and SUSE Linux | |||
|image=/resources/assets/MochiuLogo_Single_Blue.png | |||
}} | |||
__FORCETOC__ | __FORCETOC__ | ||
[[カテゴリ:Qt]] | [[カテゴリ:Qt]][[カテゴリ:Python]] |
2024年10月14日 (月) 10:57時点における最新版
概要
Qt5でPythonの開発環境を構築する時、PyQt5とPySide2の2種類が存在する。
ここでは、2種類のいくつかの差異を確認して、両方でシームレスに機能するサンプルコードを作成する手順を記載する。
これらを理解することにより、PyQt5の例からPySide2で動作するようにに変換することができる。
歴史
PyQt5とPySide2の2種類のパッケージが存在する理由を記載する。
PyQtは、Riverbank Computing社のPhilThompsonによって開発されている。
2009年にQtツールキットを所有していたNokiaは、Qt用のPythonバインディングをLGPLライセンス(Qtと同様)で利用できるようにしたいと考えていた。
Riverbank社と合意することができず、彼らはPySideとして独自のバインディングをリリースした。
2種類のインターフェースは最初は同等だったが、PySideの開発は最終的にPyQtに遅れをとっていた。(Qt5のリリース後に特に顕著だった)
PyQt5は2016年半ばから利用可能であったが、PySide2の最初の安定したリリースは2018年からである。
Qt5を使用したPythonの例の多くが、PySide2ではなくPyQt5であるのは、この遅延のせいである。
ただし、QtはPySide2を公式で採用したため、その実行可能性が確保されて、今後の人気が高まるはずである。
※注意
Sideは、フィンランド語でbinderを意味するため、PySideと呼ばれている。
PyQt 5 | PySide 2 | |
---|---|---|
最新安定版 (2021年1月現在) |
5.15 | 5.15 |
最初の安定版 | 2016年4月 | 2018年7月 |
開発者 | Riverbank Computing社 | Qt |
ライセンス形態 | GPL または コマーシャル |
LGPL |
プラットフォーム | Python 3以降 | Python 3以降 Python 2.7(Windows x86、Linux x64、MacOS) |
どちらを使用すべきか
PyQt5とPySide2はQt5をラッピングしているため、同じAPIが99.9%存在する。(いくつかの違いについては、後述のセクションを参照)
同じソースコードをそのまま使用できることが多く、import
文をPyQt5からPySide2に変更するだけである。
一方のライブラリで学習したことは、もう一方のライブラリを使用して簡単に適用できる。
例えば、PyQt5のチュートリアルを使用してPySide2を使用したソフトウェアを構築することができる。
ライセンス形態
PyQt5とPySide2のの主な違いは、ライセンス形態である。
PyQt5は、GPLまたは商用ライセンスの下で利用可能であり、PySide2はLGPLライセンスの下で利用可能である。
ソフトウェアをGPLの下でリリースする場合や配布されないソフトウェアを開発している場合、PyQt5のGPL要件が問題になる可能性はほとんどない。
ただし、ソースコードを配布せずにソフトウェアを配布する場合、Riverbank社からPyQt5の商用ライセンスを購入するか、PySide2を使用する必要がある。
LGPLライセンスでは、PySide2にバンドルされている場合でも、開発するソフトウェアのソースコードを配布する必要はない。
LGPLの対象となるソースコードが利用可能になっていることを確認するだけである。(これは、変更があった場合も含まれる)
通常の使用では変更はなく、既にPySide2 / Qt5の標準のソースコードでカバーされている。
Qt5は、Qt Commercial License、GPL2.0、GPL3.0、LGPL3.0ライセンスの下で利用できる。
UIファイル
PyQt5とPySde2は、どちらもQt CreatorまたはQt Designerからエクスポートされた.uiファイルをロードすることができる。
ただし、わずかな差異が存在するため、以下に詳細を記載する。
PyQt5は、UIファイルを読み込んでオブジェクトを生成するuicモジュールがある。
# PyQt 5
import sys
from PyQt5 import QtWidgets, uic
app = QtWidgets.QApplication(sys.argv)
window = uic.loadUi("mainwindow.ui")
window.show()
app.exec()
PySide2は、UIファイルを読み込むために、QUILoader
クラスのオブジェクトを生成する必要がある。
これらはAPI名と引数が異なる。(load
メソッドとloadUI
メソッド)
# PySide 2
import sys
from PySide2 import QtCore, QtGui, QtWidgets
from PySide2.QtUiTools import QUiLoader
app = QtWidgets.QApplication(sys.argv)
loader = QUiLoader()
window = loader.load("mainwindow.ui", None)
window.show()
app.exec_()
PyQt5の画面オブジェクト(QMainWindow.__init__等)にUIファイルを読み込むには、
uic.loadUI
メソッドを使用して、第1引数にUIファイルのパス、第2引数にself(ターゲットとなるウィジェット)を渡す。
# PyQt 5
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5 import uic
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
uic.loadUi("mainwindow.ui", self)
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
PySide2の画面オブジェクトにUIファイルを読み込むには、
load
メソッドを使用して、第1引数には、第2引数に作成しているウィジェットの親ウィジェットを渡す。
これにより、ウィジェットの__init__
ブロックにカスタムコードを追加できなくなるが、別の関数を使用してこれを回避できる。
# PySide 2
import sys
from PySide2 import QtWidgets
from PySide2.QtUiTools import QUiLoader
def mainwindow_setup(w):
w.setTitle("MainWindow Title")
app = QtWidgets.QApplication(sys.argv)
loader = QUiLoader()
window = loader.load("mainwindow.ui", None)
mainwindow_setup(window)
window.show()
app.exec()
UIファイルをPythonファイルに変換する
PyQt5とPySide2は、.uiファイルから.pyファイルへインポート可能モジュールを生成するための同一のスクリプトを提供する。
PyQt5の場合は、pyuic5をインストールして、以下のコマンドを実行する。
pyuic5 mainwindow.ui -o MainWindow.py
次に、MainWindowモジュールからUI_MainWindowクラス(使用している基本クラス(QMainWIndow等)を継承したサブクラス)をインポートして、
self.setupUI(self)
メソッドを使用して、UIを設定する。
# PyQt 5
import sys
from PyQt5 import QtWidgets
from MainWindow import Ui_MainWindow
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setupUi(self)
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
PySide2の場合、pyside2-uicをインストールして、以下のコマンドを実行する。
pyside2-uic mainwindow.ui -o MainWindow.py
後の設定は、PyQt5と同様である。
# PySide 2
import sys
from PySide2 import QtWidgets
from MainWindow import Ui_MainWindow
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setupUi(self)
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
PyQt5またはPySide2でQtDesignerを使用する方法の詳細は、Qt Creatorのチュートリアルを参照すること。
execメソッドとexec_メソッド
execメソッドはQtで使用されており、QApplicationまたはダイアログのイベントループを開始する。
Python 2.7では、execはキーワードだった経緯があり、変数、関数、メソッド名には使用できなかった。
PyQt4やPySideで実施された解決策は、この競合を回避するために、execの名前をexec_に変更することだった。
Python 3では、execキーワードを削除されており、名前を解放して使用できるようになった。
PyQt5は、Python 3のみを対象としているため回避策を取り除くことができ、execメソッド名はQt自体と同じ名前となっている。
ただし、exec_メソッド名は、下位互換性のために維持されている。
PySide2は、Python 3とPython 2.7の両方で使用できるため、引き続き、exec_メソッドを使用する。
ただし、Linux x64およびMacOSでのみ使用できる。
PyQt5とPySide2の両方をターゲットにしている場合は、exec_メソッドを使用する。
スロットとシグナル
PyQt5とPySide2のカスタムスロットとシグナルの定義では、わずかに差異があるシンタックスが使用される。
PySide2は、SignalとSlotという名前でスロットとシグナルを提供している。
PyQt5は、pyqtSignalとpyqtSlotという名前でスロットとシグナルを提供している。
これらの動作は、同じである。
以下に示すPyQt5とPySide2の例の動作は同じである。
# シグナル
my_custom_signal = pyqtSignal() # PyQt5
my_custom_signal = Signal() # PySide2
my_other_signal = pyqtSignal(int) # PyQt5
my_other_signal = Signal(int) # PySide2
# スロット
@pyqtslot
def my_custom_slot():
# Do Something
@Slot
def my_custom_slot():
# Do Something
PyQt5とPySide2の間で一貫性を確保する場合、以下のように、PyQt5またはPySide2にimportパターンを使用して、Signalおよび@Slotを定義する。
from PyQt5.QtCore import pyqtSignal as Signal, pyqtSlot as Slot
# または
from PySide2.QtCore import Signal as pyqtSignal, Slot as pyqtSlot
PyQt5とPySide2の両方のサポート
PyQt5とPySide2の両方と互換性を持たせるライブラリ、ウィジェット、その他のツールを開発している場合、
両方のインポートセットを追加することで簡単に実行できる。
以下の例は、カスタムウィジェットライブラリで使用されているアプローチであり、単一のライブラリインポートでPyQt5とPySide2をサポートしている。
注意点は、sys.modulesにあることを確認するために、sysモジュールをインポートする必要がある。
# xxx.pyファイル
import sys
if 'PyQt5' in sys.modules:
# PyQt5
from PyQt5 import QtGui, QtWidgets, QtCore
from PyQt5.QtCore import pyqtSignal as Signal, pyqtSlot as Slot
else:
# PySide2
from PySide2 import QtGui, QtWidgets, QtCore
from PySide2.QtCore import Signal, Slot
ただし、上記の方法では、複数のPythonファイルが存在する場合、各Pythonファイルで記述するため煩雑である。
この解決策は、インポートロジックを独自のファイルに移動することである。
例えば、プロジェクトのルートにqt.pyファイルを作成して、
PyQt5とPySide2のいずれかからQtモジュール(QtCore、QtGui、QtWidgets等)をインポートした後、他のPythonファイルからインポートする。
以下に、qt.pyファイルのソースコードを記述する。
他のPyQt5モジュールおよびPySide2モジュール(ブラウザ、マルチメディア等)を使用する場合、if-else
ブロックの両方に追加することを忘れないこと。
# qt.pyファイル(プロジェクトのルート)
import sys
if 'PyQt5' in sys.modules:
# PyQt5
from PyQt5 import QtGui, QtWidgets, QtCore
from PyQt5.QtCore import pyqtSignal as Signal, pyqtSlot as Slot
else:
# PySide2
from PySide2 import QtGui, QtWidgets, QtCore
from PySide2.QtCore import Signal, Slot
次に、他のPythonファイルからQt5(qt.pyファイル)をインポートする。
# xxx.pyファイル
from .qt import QtGui, QtWidgets, QtCore
その他の方法として、環境変数QT_API
を使用して、それらを切り替える方法がある。
詳細は、次のQtPyセクションを参照すること。
QtPy
QtPyは、PyQtやPySideへの単一のAPIを使用して、ソフトウェアが開発できる抽象化レイヤである。
Qt5(QtGuiモジュールがQtGuiとQtWidgetsに分割されている)を使用して、PyQt5、PyQt4、PySide2、PySideをサポートしている。
PyQt5、PyQt4、PySide2、PySide向けの標準化されたPySide2のようなAPIが提供されている。
PySide2モジュールやPyQt5モジュールの代わりに、qtpyモジュールからQtモジュールをインポートする。
QtPyを使用するには、PyQt5、PyQt4、PySide2、PySideをインストールしている必要がある。
これらのライブラリのいずれかが存在する場合、環境変数QT_APIを設定しない時は、標準でPyQt5が使用される。
環境変数QT_API
は、以下の値を取ることができる。
- pyqt5
- PyQt5を使用する。
- pyqtまたはpyqt4
- PyQt4を使用する。
- pyside2
- PySide2を使用する。
- pyside
- PySideを使用する。
QtPyをインストールするには、以下のコマンドを実行する。
pip3 install qtpy
Qt5以外のもの(PyQt 4やPySide 1等)をターゲットにする場合、QtPyのGitHubを参照すること。
QtPyを使用すると、環境変数QT_API
を使用して、ソフトウェアから読み込むAPIを制御できる。
import os
os.environ['QT_API'] = 'pyside2'
from qtpy import QtGui, QtWidgets, QtCore # imports PySide2.
エラー関連
PySide2プロジェクトを実行する時、以下のような警告が出力される場合がある。
Qt WebEngine seems to be initialized from a plugin. Please set Qt::AA_ShareOpenGLContexts using QCoreApplication::setAttribute before constructing QGuiApplication.
これは、QApplication
クラスのインスタンスを生成する前に、AA_ShareOpenGLContexts
を設定することで修正できる。
以下の例は、PySide2を使用している場合である。
from PySide2 import QtCore, QtWidgets
# ...略
if __name__ == '__main__':
QCoreApplication.setAttribute(Qt.AA_ShareOpenGLContexts)
app = QApplication(sys.argv)
# ...略
また、PySide6を使用することで警告を回避することもできる。