PySide6入門:最初のPython GUIアプリをQtで作る方法
はじめに
今日のソフトウェア開発において、使いやすく直感的なユーザーインターフェース(UI)は不可欠です。コマンドラインインターフェース(CLI)も強力ですが、多くのユーザーにとって、ボタンをクリックしたり、テキストボックスに文字を入力したりするグラフィカルユーザーインターフェース(GUI)の方が親しみやすいでしょう。
Pythonはデータ処理、Web開発、機械学習など、様々な分野で活用されていますが、GUIアプリケーション開発も例外ではありません。PythonでGUIアプリケーションを作成するためのライブラリはいくつか存在しますが、中でもPySide6は非常に強力で人気のある選択肢の一つです。
PySide6とは何か?
PySide6は、Qt Companyが提供するQtフレームワークのPythonバインディングです。「Qt for Python」とも呼ばれます。QtはC++で開発されたクロスプラットフォームのアプリケーション開発フレームワークであり、その歴史は長く、デスクトップ、モバイル、組み込みシステムなど、幅広い環境でリッチなGUIアプリケーションを構築するために世界中で利用されています。
PySide6は、この強力なQtフレームワークの機能をPythonから利用できるようにするものです。これにより、Pythonの持つ開発の容易さ、豊富なライブラリ、スクリプト言語としての柔軟性と、Qtの提供する高性能で洗練されたウィジェット、強力なグラフィックス機能、クロスプラットフォーム対応などを組み合わせた開発が可能になります。
PySide6はLGPLライセンスで提供されており、商用・非商用を問わず、多くのプロジェクトで比較的自由に利用することができます(商用ライセンスの必要性については、Qtの公式ドキュメントをご確認ください)。
なぜGUI開発にQt/PySide6を選ぶのか?
PythonでGUI開発を行うためのライブラリとしては、Tkinter(Python標準ライブラリ)、PyQt(PySideと同様のQtバインディング、GPL/商用ライセンス)、Kivy(モバイル向けにも強い)、wxPythonなど、いくつかの選択肢があります。その中でQt/PySide6を選ぶ主な理由は何でしょうか?
- クロスプラットフォーム: Windows、macOS、Linuxといった主要なデスクトップ環境だけでなく、モバイルや組み込みシステムもターゲットにできます。一つのコードベースで様々なプラットフォームに対応できるのは大きなメリットです。
- 豊富なウィジェット: Qtは非常に多様で高品質な標準ウィジェット(ボタン、ラベル、テキストボックス、リストビュー、テーブルビューなど)を提供しています。これにより、一般的なGUI要素をゼロから作る必要がありません。
- Qt Designer: GUIのデザインを直感的に行える統合ツールです。コードを書くことなく、ウィジェットの配置やプロパティの設定を行うことができ、開発効率を大幅に向上させます。
- 信号・スロットメカニズム: Qt独自の強力なイベント処理機構です。UI要素の操作(ボタンクリックなど)と、それに応じた処理(関数呼び出しなど)を柔軟かつ疎結合に連携させることができます。
- 優れたパフォーマンス: QtはC++で実装されているため、パフォーマンスが求められる処理も効率的に実行できます。特にグラフィックス関連の処理は高速です。
- 洗練されたデザイン: Qtウィジェットはデフォルトでも見栄えが良く、スタイルシート(CSSライクな構文)を使って容易にカスタマイズすることも可能です。
これらの特徴から、PySide6は本格的なデスクトップアプリケーション開発において非常に有力な選択肢となります。
この記事の目的
この記事では、PySide6を使ったGUIアプリケーション開発の第一歩を踏み出すことを目的とします。具体的には、以下の内容を学びます。
- PySide6開発環境の準備
- PySide6アプリケーションの基本的な構造
- シンプルなウィンドウの表示(Hello World)
- ウィジェットの基本的な使い方とレイアウト
- Qtのイベント処理機構「信号とスロット」
- Qt Designerを使ったUI設計の基本
- 簡単なインタラクティブアプリケーションの作成例
この記事を通して、PySide6を使ったGUI開発の楽しさと可能性を感じていただければ幸いです。
対象読者
- Pythonの基本的な文法やプログラミングの概念は理解している
- デスクトップGUIアプリケーションを自分で作ってみたい
- PySide6(またはQt)に興味がある
- GUI開発は初めて、または経験が浅い
それでは、早速PySide6の世界に足を踏み入れてみましょう!
開発環境の準備
PySide6を使った開発を始める前に、必要なものを準備しましょう。
Pythonのインストール
PySide6はPythonのライブラリですから、まずはPythonがインストールされている必要があります。多くのOSにはデフォルトでPythonがインストールされていますが、バージョンが古い場合や、システムに影響を与えたくない場合は、最新版を別途インストールすることをおすすめします。
PySide6はPython 3.6以降をサポートしています(最新の情報はPySide6の公式ドキュメントで確認してください)。開発にはPython 3.7以上のバージョンを使用するのが一般的です。
Pythonのインストール方法については、ここでは詳細を割愛しますが、公式サイトからインストーラーをダウンロードするか、パッケージマネージャー(WindowsならChocolatey、macOSならHomebrew、Linuxならaptやyumなど)を利用するのが一般的です。
仮想環境の利用 (強く推奨)
Pythonプロジェクトを開発する際には、仮想環境を利用することを強く推奨します。仮想環境は、プロジェクトごとに独立したPythonの実行環境を作成するものです。これにより、プロジェクトAで必要なライブラリのバージョンと、プロジェクトBで必要なライブラリのバージョンが衝突するのを防ぐことができます。
Python 3.3以降には、標準ライブラリとしてvenvモジュールが含まれており、これを使って簡単に仮想環境を作成できます。
仮想環境を作成したいプロジェクトのディレクトリ(例: my_gui_app)で、ターミナル(コマンドプロンプトやシェル)を開き、以下のコマンドを実行します。
bash
cd my_gui_app
python -m venv venv
これにより、my_gui_appディレクトリ内にvenvという名前のディレクトリが作成され、その中に独立したPython環境が構築されます。
次に、作成した仮想環境を「アクティベート(有効化)」します。
- Windows:
bash
venv\Scripts\activate - macOS/Linux:
bash
source venv/bin/activate
仮想環境がアクティベートされると、ターミナルのプロンプトの先頭に(venv) のような表示が追加されることが多いです。この状態でインストールしたライブラリは、この仮想環境内にのみインストールされます。
仮想環境での作業を終えるときは、deactivate コマンドを実行します。
PySide6のインストール
仮想環境をアクティベートした状態で、以下のpipコマンドを実行してPySide6をインストールします。
bash
pip install PySide6
このコマンド一つで、PySide6本体と、Qt Designerなどのツールも一緒にインストールされます。インストールが完了するまで少し時間がかかる場合があります。
インストールが成功したか確認するには、Pythonインタプリタを起動してPySide6をインポートしてみます。
“`bash
(venv) $ python
import PySide6
print(PySide6.version)
6.x.x # バージョン番号が表示されれば成功
exit()
“`
推奨されるIDEと設定
GUI開発では、コード補完やデバッグ機能が充実した統合開発環境(IDE)を使うと効率的です。よく使われるIDEとしては、Visual Studio Code (VS Code) や PyCharm などがあります。
- VS Code: 軽量で拡張機能が豊富です。Python拡張機能をインストールし、使用するPythonインタプリターとして作成した仮想環境内のものを設定します。
- PyCharm: Python開発に特化した高機能IDEです。Professional版はQt開発にも特化した機能(Qt Designerとの連携など)がありますが、Community版でも十分に開発できます。プロジェクトを作成する際に、既存の仮想環境を指定するか、PyCharmに新しい仮想環境を作成させることも可能です。
どちらのIDEを使う場合も、プロジェクトの設定で使用するPythonインタプリターとして、先ほど作成・アクティベートした仮想環境内のPythonを指定することが重要です。これにより、IDEがPySide6ライブラリを正しく認識し、コード補完やエラーチェックが機能するようになります。
Qt Designerについて
PySide6をインストールすると、Qt Designerというツールも一緒にインストールされます。Qt Designerは、GUIのユーザーインターフェースを視覚的にデザインするためのツールです。ドラッグ&ドロップでウィジェットを配置し、プロパティを設定することで、直感的にレイアウトを作成できます。
Qt Designerは、PySide6がインストールされた仮想環境内のScriptsディレクトリ(Windows)またはbinディレクトリ(macOS/Linux)に配置されます。正確な場所は環境によって異なりますが、例えばWindowsならvenv\Scripts\designer.exe、macOSならvenv/bin/Designerのようなパスになります。IDEによっては、Qt Designerを起動するための設定が用意されている場合もあります。
Qt Designerの使い方については後述しますが、GUI開発の効率を大幅に向上させる強力なツールであることを覚えておいてください。
これで、PySide6を使ったGUIアプリケーション開発を始めるための準備が整いました。
PySide6アプリケーションの基本構造
PySide6(およびQt)を使ったGUIアプリケーションは、特定の基本的な構造に従って構築されます。この構造を理解することが、開発の第一歩となります。
PySide6アプリケーションは、主に以下の要素から構成されます。
QApplicationオブジェクト:- すべてのQtアプリケーションには、必ず一つの
QApplication(またはそのサブクラス)インスタンスが必要です。 - このオブジェクトは、アプリケーション全体の制御、イベント処理ループの管理、ウィジェットの初期化、設定情報へのアクセスなどを担当します。
- コマンドライン引数を処理するため、通常は
sys.argvを引数に渡してインスタンス化します。
- すべてのQtアプリケーションには、必ず一つの
- メインウィンドウまたはトップレベルウィジェット:
- ユーザーインターフェースのルートとなるウィンドウです。これは
QMainWindow、QWidget、またはQDialogなどのクラスのインスタンスであることが多いです。 QMainWindowはメニューバー、ツールバー、ステータスバー、ドックウィジェットなどを備えた、典型的なデスクトップアプリケーションのメインウィンドウに適しています。QWidgetは最も基本的なウィジェットクラスで、他のウィジェットのコンテナとしても、独立したウィンドウとしても使用できます。QDialogは、ユーザーからの入力を受け付けたり、情報を表示したりするための一時的なウィンドウに適しています(ファイルダイアログやメッセージボックスなど)。- このウィンドウに、他の様々なウィジェット(ボタン、ラベル、テキストボックスなど)が配置されます。
- ユーザーインターフェースのルートとなるウィンドウです。これは
- ウィジェット (
QWidgetのサブクラス):- ボタン (
QPushButton)、ラベル (QLabel)、テキストボックス (QLineEdit,QTextEdit)、チェックボックス (QCheckBox) など、UIを構成する個々の部品です。 - これらのウィジェットは階層構造を持ち、メインウィンドウの中に配置されます。
- ボタン (
- レイアウトマネージャー:
- ウィンドウのサイズ変更に応じて、ウィジェットのサイズや位置を自動的に調整するための仕組みです。
QVBoxLayout(垂直方向)、QHBoxLayout(水平方向)、QGridLayout(格子状)、QFormLayout(フォーム形式)などがあります。 - レイアウトマネージャーを使用することで、異なる画面サイズや解像度でもUIが崩れないように設計できます。
- ウィンドウのサイズ変更に応じて、ウィジェットのサイズや位置を自動的に調整するための仕組みです。
- イベントループ:
- GUIアプリケーションは、ユーザー操作(マウスのクリック、キーボード入力など)やシステムイベント(ウィンドウのリサイズ、ペイント要求など)に応答して動作します。
- これらのイベントを監視し、適切なウィジェットやオブジェクトにディスパッチ(振り分け)するのがイベントループです。
QApplicationのexec()またはexec_()メソッドを呼び出すことで、イベントループが開始されます。アプリケーションはこのイベントループが終了するまで実行され続けます。
基本的なコードテンプレート
これらの要素を踏まえると、PySide6アプリケーションの最も基本的なコードは以下のようになります。
“`python
import sys
from PySide6.QtWidgets import QApplication, QWidget, QLabel
1. QApplicationオブジェクトを作成する
アプリケーション全体の制御を担当
app = QApplication(sys.argv)
2. メインウィンドウ(またはトップレベルウィジェット)を作成する
今回は最もシンプルなQWidgetを使用
window = QWidget()
window.setWindowTitle(“My First PySide6 App”) # ウィンドウのタイトルを設定
window.setGeometry(100, 100, 400, 300) # ウィンドウの位置とサイズ (x, y, width, height)
ウィジェットを配置することも可能だが、この例ではシンプルにウィンドウだけ
label = QLabel(“Hello, PySide6!”, parent=window)
label.move(150, 100) # ウィジェットの左上隅の位置を指定
3. ウィンドウを表示する
window.show()
4. アプリケーションのイベントループを開始する
ユーザーがウィンドウを閉じるまで実行され続ける
sys.exit(app.exec())
“`
このコードを実行すると、タイトルバーに「My First PySide6 App」と表示された、空のウィンドウが表示されます。ウィンドウを閉じるとアプリケーションが終了します。
import sys: コマンドライン引数(sys.argv)を取得するために必要です。from PySide6.QtWidgets import QApplication, QWidget, QLabel: 使用するQtウィジェットクラスをインポートします。QtWidgetsモジュールには、GUIアプリケーションでよく使う標準ウィジェットのほとんどが含まれています。app = QApplication(sys.argv):QApplicationのインスタンスを作成します。アプリケーションは起動時に受け取るコマンドライン引数を処理する場合がありますが、通常はそのままsys.argvを渡せばOKです。window = QWidget(): 最も基本的なウィジェットであるQWidgetのインスタンスを作成し、これをメインウィンドウとして使用します。window.setWindowTitle(...): ウィンドウのタイトルバーに表示されるテキストを設定します。window.setGeometry(x, y, width, height): ウィンドウが画面上のどこに、どのくらいのサイズで表示されるかを指定します。xとyは画面左上からの座標、widthとheightはウィンドウの幅と高さです。window.show(): 作成したウィンドウを画面に表示します。ウィジェットは作成しただけでは表示されず、show()メソッドを呼び出す必要があります。sys.exit(app.exec()):QApplicationのイベントループを開始します。アプリケーションが終了すると、exec()メソッドは終了コード(通常は0が成功)を返します。sys.exit()はその終了コードでPythonスクリプト自体を終了させます。これがPySide6アプリケーションの実行における最後の、そして最も重要なステップです。
この基本的な構造を理解しておけば、どのようなPySide6アプリケーションでも、このテンプレートの上にウィジェットを追加したり、イベント処理を追加したりしていくことで構築できることが分かります。
最初のGUIアプリケーションを作成する (Hello World)
前のセクションの基本的な構造を使って、「Hello, PySide6!」と表示する簡単なGUIアプリケーションを作成してみましょう。
シンプルなウィンドウとラベルを表示するコード
“`python
import sys
from PySide6.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout
from PySide6.QtCore import Qt
1. QApplicationオブジェクトを作成
app = QApplication(sys.argv)
2. メインウィンドウ(今回はQWidgetを使用)を作成
window = QWidget()
window.setWindowTitle(“Hello PySide6 App”)
window.setGeometry(100, 100, 300, 150) # 少し小さめのウィンドウ
3. ウィジェットを作成 – ラベル
label = QLabel(“
Hello, PySide6!
“) # HTMLタグも使える
label.setAlignment(Qt.AlignmentFlag.AlignCenter) # テキストを中央揃えに
4. レイアウトを作成し、ウィジェットを追加
ウィンドウに直接ウィジェットを配置する代わりに、レイアウトを使う
layout = QVBoxLayout() # 垂直方向のレイアウト
layout.addWidget(label) # ラベルをレイアウトに追加
5. ウィンドウにレイアウトを設定
window.setLayout(layout)
6. ウィンドウを表示
window.show()
7. アプリケーションのイベントループを開始
sys.exit(app.exec())
“`
コードの説明
from PySide6.QtCore import Qt:Qtモジュールから、アライメントフラグ(Qt.AlignmentFlag.AlignCenterなど)のような共通の定数をインポートします。label = QLabel(...):QLabelウィジェットを作成します。QLabelはテキストや画像を表示するために使われます。ここではHTMLタグを使って、テキストの一部を装飾しています。Qtの多くのウィジェットはリッチテキスト(HTMLサブセット)をサポートしています。label.setAlignment(Qt.AlignmentFlag.AlignCenter): ラベル内のテキストを水平方向と垂直方向の中央に揃えます。Qt.AlignmentFlagはQtの定数グループです。layout = QVBoxLayout(): ウィジェットを垂直方向に並べるためのレイアウトマネージャーであるQVBoxLayoutのインスタンスを作成します。layout.addWidget(label): 作成したlabelウィジェットをlayoutに追加します。レイアウトにウィジェットを追加すると、レイアウトマネージャーがウィジェットの位置とサイズを管理するようになります。window.setLayout(layout): 作成したlayoutをwindowのメインレイアウトとして設定します。これにより、windowは内部のウィジェットの配置をこのレイアウトマネージャーに任せるようになります。手動でlabel.move()などを使って座標を指定する必要がなくなります。レイアウトマネージャーは、ウィンドウサイズが変更されたときにもウィジェットの配置を適切に更新してくれます。
このコードを実行すると、タイトルが「Hello PySide6 App」で、中央に「Hello, PySide6!」と表示されたウィンドウが表示されます。ウィンドウサイズを変更しても、テキストは中央に表示され続けます。
実行方法
このコードを例えばhello_app.pyというファイル名で保存します。
仮想環境をアクティベートしたターミナルを開き、以下のコマンドを実行します。
bash
(venv) $ python hello_app.py
これで、あなたの最初のPySide6 GUIアプリケーションが起動するはずです。
この簡単な例から、QApplicationによる全体管理、QWidgetによるウィンドウ作成、QLabelによる要素表示、そしてQVBoxLayoutによる配置の基本が理解できたかと思います。特にレイアウトマネージャーの利用は、柔軟なUIを作成する上で非常に重要です。
ウィジェットの配置と基本的なプロパティ
GUIアプリケーションは、様々な機能を持つウィジェットの組み合わせによって構成されます。このセクションでは、よく使われる基本的なウィジェットを紹介し、ウィンドウ内での配置(レイアウト)について詳しく見ていきます。
よく使うウィジェットの紹介
PySide6はQtが提供する豊富なウィジェットを利用できます。ここでは、代表的なものをいくつか紹介します。
QLabel: テキストや画像を表示します。編集はできません。QPushButton: クリック可能なボタンです。何らかのアクションを実行する際に使います。QLineEdit: 一行のテキスト入力フィールドです。ユーザーからの短い入力を受け付けるのに使います。QTextEdit: 複数行のテキスト入力・表示フィールドです。リッチテキストも扱えます。QCheckBox: チェック可能な四角いボックスです。オン/オフの状態を示したり、ユーザーに選択肢を選ばせたりします。QRadioButton: 丸いラジオボタンです。通常、複数の選択肢の中から一つだけを選ぶ形式で使われます(同じ親ウィジェット内に配置されたQRadioButtonは自動的にグループ化されます)。QComboBox: ドロップダウンリストです。複数の選択肢の中から一つを選ぶ際に、スペースを節約したい場合に便利です。QSlider: スライダーです。数値範囲の中から値を選択させるのに使います。QProgressBar: プログレスバーです。タスクの進行状況を表示します。QListWidget: アイテムのリストを表示します。アイテムの選択や追加/削除が可能です。QTableWidget: 行と列を持つテーブル形式でデータを表示・編集します。
これらのウィジェットはすべてQWidgetクラスを継承しており、共通の基本的なプロパティやメソッドを持っています(例: setGeometry(), move(), resize(), setVisible(), setEnabled(), setToolTip()など)。
ウィジェットの作成とウィンドウへの追加
ウィジェットは、クラスをインスタンス化することで作成します。多くのウィジェットのコンストラクタは、最初の引数として親ウィジェットを指定できます。親を指定しない場合、そのウィジェットは独立したウィンドウとして表示されます。メインウィンドウ内に配置するウィジェットは、通常、メインウィンドウ自身や、メインウィンドウ内の別のコンテナウィジェット(例: グループボックス)を親として指定します。
“`python
例: ボタンとラベルを作成し、親を指定
main_window = QWidget() # メインウィンドウ
button = QPushButton(“Click Me”, parent=main_window) # 親をmain_windowに指定
label = QLabel(“Status:”, parent=main_window) # 親をmain_windowに指定
“`
親を指定することで、ウィジェットは親ウィジェット内で表示され、親ウィジェットが破棄されるときに一緒に破棄されます。
レイアウトマネージャーの概念
前述のHello Worldの例でも触れましたが、ウィジェットをウィンドウ内に配置する方法には大きく分けて二つあります。
- 手動での配置: 各ウィジェットに対して
move(x, y)メソッドを呼び出し、絶対座標で位置を指定する方法です。シンプルですが、ウィンドウサイズが変わったときにウィジェットの位置やサイズは自動的に調整されません。 - レイアウトマネージャーの使用: ウィジェットを特定のレイアウトマネージャー(
QVBoxLayout,QHBoxLayout,QGridLayoutなど)に追加し、そのレイアウトを親ウィジェットに設定する方法です。レイアウトマネージャーがウィジェットのサイズと位置を自動的に計算・管理してくれます。ウィンドウサイズが変更されたときも、レイアウトマネージャーが再計算を行い、UIが適切に調整されます。
本格的なGUIアプリケーションでは、ウィンドウサイズの変化に柔軟に対応できるレイアウトマネージャーを使用するのが一般的です。特別な理由がない限り、レイアウトマネージャーを使いましょう。
主なレイアウトマネージャー
PySide6にはいくつかの主要なレイアウトマネージャーがあります。
QVBoxLayout: 子ウィジェットを垂直方向に並べます。QHBoxLayout: 子ウィジェットを水平方向に並べます。QGridLayout: 子ウィジェットを格子状(行と列)に配置します。各ウィジェットを特定のセル(行番号、列番号)に配置したり、複数のセルをまたがって配置したりできます。QFormLayout: ラベルと入力ウィジェットのペアを、フォーム形式で配置します。設定画面などによく使われます。
これらのレイアウトマネージャーは、入れ子にして使用することも可能です。例えば、ウィンドウの最上部に垂直方向のレイアウト(QVBoxLayout)を置き、その中の要素として、水平方向のレイアウト(QHBoxLayout)や別の垂直方向のレイアウトを配置することで、複雑なUI構成を実現できます。
簡単なレイアウトの例 (QVBoxLayoutとQHBoxLayoutの組み合わせ)
ボタンを2つ水平に並べ、その下にラベルを垂直に配置する例を見てみましょう。
“`python
import sys
from PySide6.QtWidgets import (QApplication, QWidget, QPushButton, QLabel,
QVBoxLayout, QHBoxLayout)
from PySide6.QtCore import Qt
app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle(“Layout Example”)
window.setGeometry(100, 100, 400, 200)
垂直方向の親レイアウトを作成
main_layout = QVBoxLayout()
水平方向の子レイアウトを作成(ボタン用)
button_layout = QHBoxLayout()
ボタンを作成し、水平レイアウトに追加
button1 = QPushButton(“Button 1”)
button2 = QPushButton(“Button 2”)
button_layout.addWidget(button1)
button_layout.addWidget(button2)
ボタンの間にスペースを入れることもできる
button_layout.addStretch() # 伸縮可能なスペース
ラベルを作成
label = QLabel(“Status: Waiting…”)
label.setAlignment(Qt.AlignmentFlag.AlignCenter)
label.setStyleSheet(“border: 1px solid gray;”) # 見やすくするために枠線を付ける
水平レイアウトとラベルを垂直レイアウトに追加
main_layout.addLayout(button_layout) # レイアウト自体を追加
main_layout.addWidget(label) # ウィジェットを追加
メインウィンドウに垂直レイアウトを設定
window.setLayout(main_layout)
window.show()
sys.exit(app.exec())
“`
このコードを実行すると、ウィンドウ上部に「Button 1」と「Button 2」が横に並び、その下に「Status: Waiting…」というラベルが表示されます。ウィンドウサイズを変更すると、ウィジェットの位置とサイズがレイアウトに従って自動調整されます。
main_layout = QVBoxLayout(): ウィンドウ全体のレイアウトとして、垂直方向のレイアウトを作成します。button_layout = QHBoxLayout(): ボタンを水平に並べるためのレイアウトを作成します。button_layout.addWidget(button1):button1を水平レイアウトに追加します。次に追加されるウィジェットはその右に配置されます。main_layout.addLayout(button_layout): 垂直レイアウトに、先ほど作成した水平レイアウトそのものを追加します。これにより、水平レイアウト内のウィジェット(ボタン)が一つのまとまりとして垂直方向の要素として扱われます。main_layout.addWidget(label): 垂直レイアウトにlabelウィジェットを追加します。これは水平レイアウト(ボタンのまとまり)の下に配置されます。
このように、レイアウトマネージャーを組み合わせることで、複雑なレイアウトを効率的に構築できます。
ウィジェットの基本的なプロパティ
各ウィジェットには、見た目や振る舞いを制御するための様々なプロパティがあります。Qt Designerを使うとこれらのプロパティをGUIで設定できますが、コードから設定することも頻繁に行います。
例:
* widget.setWindowTitle("Title"): ウィンドウのタイトルを設定
* widget.setGeometry(x, y, w, h): 位置とサイズを設定
* widget.resize(w, h): サイズを設定
* widget.move(x, y): 位置を設定
* widget.setToolTip("Hint text"): ウィジェットにマウスカーソルを合わせたときに表示されるツールチップを設定
* widget.setEnabled(False): ウィジェットを無効化(グレー表示になり操作できなくなる)
* widget.setVisible(False): ウィジェットを非表示にする
* widget.setStyleSheet("property: value;"): CSSライクな構文でウィジェットのスタイルを設定(色、フォント、ボーダーなど)
これらのプロパティは、必要に応じてQtのドキュメントを参照しながら使いこなしていくことになります。
信号とスロット (Signals & Slots)
GUIアプリケーションでは、ユーザー操作やシステムイベントに対して何らかの処理を実行する必要があります。例えば、ボタンがクリックされたら特定の関数を実行する、テキストボックスの入力内容が変わったら警告を表示するなどです。
Qtフレームワークでは、このようなイベント処理を信号(Signals)とスロット(Slots)という独自の強力なメカニズムで行います。これはPySide6開発において最も理解すべき重要な概念の一つです。
信号 (Signal) とは何か?
信号は、あるイベントが発生したことを他のオブジェクトに知らせるために、オブジェクトが発信するメッセージのようなものです。
- 例:
QPushButtonオブジェクトは、ユーザーがボタンをクリックしたときにclicked()という信号を発信します。QLineEditオブジェクトは、テキストの内容が変更されるたびにtextChanged(text)という信号を発信します(textは新しい内容)。 - 信号は特定のイベントに関連付けられており、そのイベントが発生すると自動的に発信されます。
- 信号自体は、何らかの処理を実行するものではなく、あくまで「イベントが発生した」という事実を知らせるだけです。
スロット (Slot) とは何か?
スロットは、信号を受け取って実行される関数またはメソッドです。
- スロットは、特定の処理を実行するための通常のPython関数やクラスのメソッドです。
- 信号は、一つまたは複数のスロットに接続(Connect)することができます。信号が発信されると、それに接続されているすべてのスロットが自動的に呼び出されます。
- スロットは、信号が発信するデータ(引数)を受け取ることができます。例えば、
QLineEditのtextChanged(text)信号は、新しいテキスト内容を引数textとしてスロットに渡します。
信号とスロットの接続方法
信号とスロットを関連付けるには、信号オブジェクトのconnect()メソッドを使用します。
基本的な構文は以下のようになります。
python
signal.connect(slot)
signal: 接続したい信号オブジェクト(例:button.clicked)slot: 信号が発信されたときに実行したい関数またはメソッド(例:my_functionまたはself.my_method)
注意点: 信号オブジェクトを参照する際は、信号名の後に()を付けません(例: button.clickedであってbutton.clicked()ではない)。()を付けると、それは信号を発信する(エミットする)メソッド呼び出しと見なされてしまいます。
簡単な例 (ボタンクリックでメッセージを表示する)
ボタンをクリックしたら、ターミナルにメッセージを表示する簡単な例を作成してみましょう。
“`python
import sys
from PySide6.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout
スロットとして使用する関数
def handle_button_click():
print(“Button was clicked!”)
app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle(“Signal and Slot Example”)
window.setGeometry(100, 100, 300, 100)
ボタンを作成
button = QPushButton(“Click Me!”)
スロットとして使用する関数を定義
def on_button_clicked():
print(“The button was clicked!”)
# ここにボタンがクリックされたときの処理を書く
信号(clicked)とスロット(on_button_clicked関数)を接続
button.clicked.connect(on_button_clicked)
レイアウトを作成し、ボタンを追加
layout = QVBoxLayout()
layout.addWidget(button)
window.setLayout(layout)
window.show()
sys.exit(app.exec())
“`
このコードを実行すると、ボタンが表示されたウィンドウが現れます。「Click Me!」ボタンをクリックすると、ターミナルに「The button was clicked!」というメッセージが表示されます。
on_button_clicked(): これはボタンがクリックされたときに実行したい処理を記述した普通のPython関数です。button.clicked.connect(on_button_clicked): ここで、buttonオブジェクトのclicked信号と、on_button_clicked関数を接続しています。ボタンがクリックされてclicked信号が発信されると、この接続によってon_button_clicked関数が呼び出されます。
シグネチャ(信号が持つ引数)
信号によっては、イベントに関する情報(例: チェックボックスの新しい状態、スライダーの値など)を引数としてスロットに渡すものがあります。スロットとして接続する関数は、信号のシグネチャ(引数の型と数)と一致するか、それを受け取れるような形で定義されている必要があります。
例: QCheckBoxのtoggled(bool checked)信号は、チェック状態(TrueまたはFalse)を引数に渡します。
“`python
import sys
from PySide6.QtWidgets import QApplication, QWidget, QCheckBox, QVBoxLayout
def on_checkbox_toggled(checked):
if checked:
print(“Checkbox is checked!”)
else:
print(“Checkbox is unchecked!”)
app = QApplication(sys.argv)
window = QWidget()
layout = QVBoxLayout()
checkbox = QCheckBox(“Check me”)
checkbox.toggled.connect(on_checkbox_toggled) # 引数を受け取るスロットを接続
layout.addWidget(checkbox)
window.setLayout(layout)
window.show()
sys.exit(app.exec())
“`
この例では、on_checkbox_toggled関数がcheckedという引数を受け取っています。QCheckBoxがチェックされるとtoggled(True)信号が、チェックが外れるとtoggled(False)信号が発信され、それぞれchecked引数にTrueまたはFalseが渡されてスロットが実行されます。
スロットとしてのクラスメソッド
クラスを定義してGUIを構築する場合、スロットとしてはクラスのメソッドを使用することがほとんどです。
“`python
import sys
from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton, QLabel, QVBoxLayout, QWidget
class MyMainWindow(QMainWindow):
def init(self):
super().init()
self.setWindowTitle("Method Slot Example")
self.setGeometry(100, 100, 300, 150)
layout = QVBoxLayout()
self.label = QLabel("Status: Ready")
layout.addWidget(self.label)
button = QPushButton("Update Status")
# クラスのメソッドをスロットとして接続
button.clicked.connect(self.update_status)
layout.addWidget(button)
central_widget = QWidget()
central_widget.setLayout(layout)
self.setCentralWidget(central_widget)
# スロットとして使用するメソッド
def update_status(self):
print("Button clicked, updating status...")
self.label.setText("Status: Updated!")
if name == “main“:
app = QApplication(sys.argv)
main_window = MyMainWindow()
main_window.show()
sys.exit(app.exec())
“`
この例では、MyMainWindowクラスのインスタンスメソッドであるupdate_statusをボタンのclicked信号のスロットとして接続しています。ボタンがクリックされるとupdate_statusメソッドが実行され、ラベルのテキストが更新されます。
信号とスロットは、Qtアプリケーションのイベント処理の核となる非常に強力なメカニズムです。これを使いこなすことで、UI要素間のインタラクションを柔軟に構築できます。
Qt Designerを使ったUI設計
コードでGUIを構築することも可能ですが、特に複雑なUIの場合、ウィジェットの配置やプロパティの設定をすべて手書きするのは非常に手間がかかります。ここで威力を発揮するのが、PySide6のインストール時に含まれるQt Designerです。
Qt Designerを使うと、ウィンドウの外観を視覚的にデザインし、そのデザインを.uiという拡張子を持つXMLファイルとして保存できます。この.uiファイルを後でPythonコードから読み込んで利用することで、UIの設計とアプリケーションのロジック開発を分離できます。
Qt Designerの起動方法
PySide6を仮想環境にインストールした場合、Qt Designerは仮想環境内の特定のディレクトリにインストールされます。
- Windows:
仮想環境ディレクトリ\Scripts\designer.exe - macOS/Linux:
仮想環境ディレクトリ/bin/Designer
正確なパスは環境によって異なりますが、通常はpip listでPySide6がインストールされていることを確認した後、仮想環境の実行ファイルがあるディレクトリを探すと見つかります。IDE(PyCharm Professionalなど)によっては、IDE内からQt Designerを起動する機能が統合されています。
Qt Designerを起動すると、新しいフォームを作成するためのダイアログが表示されます。ここでは、典型的なメインウィンドウである「Main Window」を選択して「作成」をクリックしてみましょう。
Qt Designerの基本的な使い方
Qt Designerの画面は、主に以下の領域に分かれています。
- ウィジェットボックス: 左側に表示される、利用可能なウィジェットのリストです(Layouts, Spacers, Buttons, Display Widgets, Input Widgetsなど)。ここからウィジェットを選んでフォームにドラッグ&ドロップします。
- フォームエディタ: 中央の広い領域で、GUIをデザインするキャンバスです。ウィジェットを配置したり、サイズや位置を調整したりします。
- オブジェクトインスペクタ: 右上部分に表示され、フォーム上のウィジェットの階層構造を表示します。ウィジェットの選択や名前の確認に便利です。
- プロパティエディタ: 右下部分に表示され、選択中のウィジェットのプロパティ(テキスト、サイズ、有効/無効、スタイルなど)を編集できます。
- シグナル/スロットエディタ: フォーム下部または別のモードで表示され、UI上のウィジェットの信号と、それに応答するスロットを視覚的に接続できます(ただし、PySide6ではこの機能はあまり使われず、Pythonコードで接続するのが一般的です)。
基本的な操作:
- ウィジェットボックスから必要なウィジェットをフォームエディタにドラッグ&ドロップします。
- 配置したウィジェットをクリックして選択します。プロパティエディタでウィジェットの名前(
objectName)やその他のプロパティを変更できます。objectNameはPythonコードからウィジェットを参照する際に重要になります。 - 複数のウィジェットを選択し、フォームエディタ上部のツールバーにあるレイアウトボタン(垂直レイアウト、水平レイアウト、格子レイアウトなど)をクリックすると、選択したウィジェットが自動的にレイアウト内に配置されます。または、レイアウトオブジェクト(
Vertical Layoutなど)をドラッグ&ドロップし、その中にウィジェットを配置することもできます。 - メインウィンドウ全体のレイアウトを設定するには、ウィンドウの何もない部分をクリックしてウィンドウ自体を選択し、右クリックメニューから「レイアウト」→「垂直レイアウト」や「格子レイアウト」などを選択します。ウィンドウ内のすべてのウィジェットがそのレイアウトに従って配置されます。
- デザインが完了したら、「ファイル」→「保存」を選択し、
.ui拡張子でファイルを保存します(例:mainwindow.ui)。
.uiファイルをPythonコードから利用する方法
Qt Designerで作成した.uiファイルを利用する方法は主に二つあります。
方法1: uic.loadUi() を使う方法 (手軽)
これは最も手軽な方法です。実行時に.uiファイルを読み込み、そこからGUIを構築します。
“`python
import sys
from PySide6.QtWidgets import QApplication, QMainWindow
from PySide6.QtUiTools import QUiLoader # このクラスを使う
uiファイルを読み込むためのローダー
loader = QUiLoader()
app = QApplication(sys.argv)
uiファイルを読み込んでウィンドウを作成
loader.load() の第一引数は ui ファイルのパス
第二引数は親ウィジェット (QMainWindow なので None でもよい)
window = loader.load(“mainwindow.ui”, None)
ウィンドウを表示
window.show()
sys.exit(app.exec())
“`
この方法の利点は、デザイン変更があった場合に.uiファイルを置き換えるだけで済み、Pythonコード自体を変更する必要がないことです。しかし、PythonコードからUI上の特定のウィジェット(例: ボタンやラベル)を参照して信号を接続したりプロパティを変更したりするには、少々工夫が必要です。loader.load()が返すオブジェクト(この例ではwindow)の属性として、Qt Designerで設定したobjectNameの名前でウィジェットにアクセスできます。
“`python
例: mainwindow.ui に objectName が ‘myButton’ の QPushButton がある場合
uiファイルを読み込んだ後で…
button = window.findChild(QPushButton, “myButton”) # または単に window.myButton でもアクセスできることが多い
if button:
button.clicked.connect(some_slot)
“`
方法2: pyside6-uic コマンドで.pyファイルに変換し、それをクラスとして利用する方法 (より一般的)
この方法では、Qt Designerで作成した.uiファイルを、PySide6のコードが記述されたPythonファイルに変換します。そして、そのPythonファイルで定義されたUIクラスを、自分のアプリケーションクラスから継承して利用します。
まず、ターミナル(仮想環境をアクティベートした状態)で以下のコマンドを実行し、.uiファイルをPythonファイルに変換します。
bash
pyside6-uic mainwindow.ui -o ui_mainwindow.py
pyside6-uic: PySide6に含まれるUIコンバーターコマンドです。mainwindow.ui: 変換元の.uiファイル名です。-o ui_mainwindow.py: 変換結果を保存するPythonファイル名です。慣例として、ui_プレフィックスを付けることが多いです。
このコマンドを実行すると、ui_mainwindow.pyというファイルが生成されます。このファイルの中には、UIを構築するためのコードと、Ui_MainWindowのような名前のクラスが定義されています。
次に、自分のアプリケーションのメインウィンドウクラスを作成し、このUi_MainWindowクラスを継承して利用します。
“`python
import sys
from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton, QLabel
Qt Designerから変換されたUIクラスをインポート
from ui_mainwindow import Ui_MainWindow
class MyMainWindow(QMainWindow, Ui_MainWindow): # QMainWindow と Ui_MainWindow を両方継承
def init(self):
super().init() # QMainWindow のコンストラクタを呼び出す
# UIセットアップメソッドを呼び出す
# ui_mainwindow.py で定義されている setupUi メソッドが実行され、
# ウィジェットの作成、プロパティ設定、レイアウト設定が行われる
self.setupUi(self)
# ここから、Qt Designerで配置したウィジェットにアクセスしてロジックを追加
# ウィジェットには objectName でアクセスできる (setupUi が self の属性として設定する)
self.label.setText("Initialized via Code") # 例: ラベルのテキストを変更
self.myButton.clicked.connect(self.on_my_button_clicked) # 例: ボタンの信号を接続
# ボタンのクリックイベントに対応するスロット
def on_my_button_clicked(self):
print("Button clicked from converted UI!")
self.label.setText("Button Clicked!")
if name == “main“:
app = QApplication(sys.argv)
main_window = MyMainWindow()
main_window.show()
sys.exit(app.exec())
“`
この方法の利点は以下の通りです。
- Pythonコード内で、Qt Designerで設定した
objectNameをそのまま属性名としてウィジェットにアクセスできるため、コードが読みやすくなります(例:self.myButton,self.label)。 - アプリケーションのロジック(信号とスロットの接続、データの処理など)を記述するクラスと、UIの定義を分離できます。
- Qt DesignerでUIを変更した場合は、再度
pyside6-uicコマンドを実行して.pyファイルを更新するだけで、アプリケーションのロジックコード自体は変更せずにUIの変更を反映できます(ただし、objectNameを変更した場合は、コード内の参照箇所も修正が必要です)。
一般的には、pyside6-uicで.pyファイルに変換して利用する方法が推奨されます。UIデザインとロジックの役割分担が明確になり、保守性が高まるためです。
どちらの方法でも、Qt Designerを使うことでGUIデザインにかかる労力を大幅に削減し、より複雑なUIも効率的に構築できるようになります。
より実践的なアプリケーションの作成
これまでに学んだPySide6の基本(ウィンドウ、ウィジェット、レイアウト、信号とスロット、Qt Designerの利用)を組み合わせて、より実践的な小さなアプリケーションを作成してみましょう。ここでは、テキスト入力とボタンを使って、入力されたテキストを別のラベルに表示するシンプルな例を考えます。
この例では、pyside6-uicを使ってQt DesignerでUIを作成し、そのUIをPythonコードで利用する方式を採用します。
1. Qt DesignerでUIを作成
まず、Qt Designerを起動し、新しい「Main Window」を作成します。
以下のウィジェットを配置します。
QLabel: 「Enter your name:」のような指示テキスト用。objectNameはデフォルト(例:label)でOK。QLineEdit: ユーザーが名前を入力するテキストボックス。objectNameをnameLineEditに変更します。QPushButton: アクション実行用ボタン。「Submit」のようなテキストを設定。objectNameをsubmitButtonに変更します。QLabel: 結果表示用。初期テキストは空にするか「Result:」などにしておきます。objectNameをresultLabelに変更します。
これらのウィジェットを適切なレイアウトに配置します。例えば、垂直レイアウト(QVBoxLayout)をウィンドウのメインレイアウトとし、その中に以下の順でウィジェットを追加します。
QLabel(指示テキスト)QLineEdit(入力フィールド)QPushButton(ボタン)QLabel(結果表示用)
ファイルメニューから「保存」を選び、例えばname_input_ui.uiという名前で保存します。
2. .uiファイルをPythonコードに変換
保存した.uiファイルを、ターミナルでpyside6-uicコマンドを使ってPythonファイルに変換します。
bash
pyside6-uic name_input_ui.ui -o ui_name_input.py
これでui_name_input.pyというファイルが生成されます。このファイルを開いてみると、先ほど配置したウィジェットの作成コードやレイアウト設定コード、そしてUi_MainWindowというクラスが定義されているのが確認できます。
3. アプリケーションのロジックを記述
次に、ui_name_input.pyで定義されたUIクラスを利用し、アプリケーションのロジック(ボタンがクリックされたら、テキスト入力フィールドの内容を取得し、結果表示ラベルにセットする)を記述するPythonファイルを作成します。例えばapp.pyという名前で保存します。
“`python
import sys
from PySide6.QtWidgets import QApplication, QMainWindow
生成されたUIクラスをインポート
from ui_name_input import Ui_MainWindow
class NameInputApp(QMainWindow, Ui_MainWindow):
def init(self):
super().init()
# UIのセットアップ(ウィジェット作成とレイアウト設定)
self.setupUi(self)
# ----------- ここからカスタムロジックを追加 -----------
# 1. ウィジェットへのアクセス
# setupUi()によって、Qt Designerで設定した objectName でウィジェットにアクセスできるようになる
# self.nameLineEdit # 入力用QLineEdit
# self.submitButton # ボタン
# self.resultLabel # 結果表示用QLabel
# 2. 信号とスロットの接続
# submitButton の clicked 信号を、自作メソッド on_submit_button_clicked に接続
self.submitButton.clicked.connect(self.on_submit_button_clicked)
# ----------------------------------------------------
# スロットメソッド:Submitボタンがクリックされたときに実行される
def on_submit_button_clicked(self):
# 1. QLineEditからテキストを取得
name = self.nameLineEdit.text()
# 2. QLabelに結果を表示
if name: # 名前が入力されているかチェック
self.resultLabel.setText(f"Hello, {name}!")
else:
self.resultLabel.setText("Please enter your name.")
アプリケーションのエントリーポイント
if name == “main“:
app = QApplication(sys.argv)
main_window = NameInputApp() # 作成したカスタムウィンドウクラスのインスタンスを作成
main_window.show() # ウィンドウを表示
sys.exit(app.exec()) # イベントループを開始
“`
コードの説明
from ui_name_input import Ui_MainWindow:pyside6-uicコマンドで生成されたファイルからUi_MainWindowクラスをインポートしています。class NameInputApp(QMainWindow, Ui_MainWindow):: 自分のアプリケーションのメインウィンドウクラスNameInputAppを定義しています。このクラスは、PySide6の標準的なメインウィンドウクラスであるQMainWindowと、UI定義を含むUi_MainWindowクラスの両方を継承しています。これはPythonの多重継承を利用したQt開発の一般的なパターンです。super().__init__(): 親クラス(QMainWindowとUi_MainWindow)のコンストラクタを呼び出します。特にQMainWindowの初期化が必要です。self.setupUi(self):Ui_MainWindowクラスで定義されているsetupUiメソッドを呼び出します。このメソッドは引数として渡されたウィンドウオブジェクト(ここではself、つまりNameInputAppのインスタンス自身)に対して、Qt Designerで定義されたUI(ウィジェットの作成、プロパティ設定、レイアウト設定)を適用します。この処理が終わった時点で、selfオブジェクトは、Qt Designerで配置した各ウィジェット(objectNameで指定した名前)を属性として持つようになります。self.submitButton.clicked.connect(self.on_submit_button_clicked): Qt DesignerでobjectNameをsubmitButtonとしたQPushButtonオブジェクトにアクセスし、そのclicked信号を、クラス内で定義したon_submit_button_clickedメソッドに接続しています。on_submit_button_clicked(self): このメソッドがボタンクリックのスロットです。name = self.nameLineEdit.text(): Qt DesignerでobjectNameをnameLineEditとしたQLineEditオブジェクトにアクセスし、そのtext()メソッドを呼び出して現在の入力内容を取得しています。self.resultLabel.setText(...): Qt DesignerでobjectNameをresultLabelとしたQLabelオブジェクトにアクセスし、そのsetText()メソッドを使って表示内容を更新しています。
実行
ui_name_input.pyとapp.pyが同じディレクトリにあることを確認し、仮想環境をアクティベートしたターミナルで以下を実行します。
bash
(venv) $ python app.py
実行すると、Qt Designerでデザインした通りのウィンドウが表示されます。テキストボックスに何か入力して「Submit」ボタンをクリックすると、その入力内容が下のラベルに表示されるはずです。
この例は非常にシンプルですが、以下の重要な開発パターンを示しています。
- UIデザインとアプリケーションロジックの分離
- Qt Designerで作成したUIを
pyside6-uicで変換し、Pythonクラスに統合する方法 - PythonコードからUI上のウィジェットにアクセスする方法
- 信号とスロットを使ってUI操作に応じた処理を実行する方法
このパターンは、より複雑なQtアプリケーション開発の基礎となります。
ファイルダイアログやメッセージボックス
本格的なGUIアプリケーションでは、ファイルを開いたり保存したり、ユーザーに確認を求めたり、エラーメッセージを表示したりする際に、標準的なダイアログを使用することがよくあります。PySide6は、Qtの提供する豊富な標準ダイアログクラスを利用できます。
よく使うダイアログクラスを紹介します。
QFileDialog: ファイルを開くダイアログ、ファイルを保存するダイアログ、ディレクトリを選択するダイアログなどを提供します。QMessageBox: 情報、警告、エラー、質問、アバウトなどの標準的なメッセージボックスを表示します。ユーザーにOK/キャンセルなどのボタンをクリックさせて応答を取得することもできます。QFontDialog: フォントを選択するダイアログ。QColorDialog: 色を選択するダイアログ。
これらのダイアログは通常、モーダルダイアログとして表示されます。モーダルダイアログとは、それが表示されている間は親ウィンドウや他のウィンドウの操作がブロックされる種類のウィンドウです。ユーザーがダイアログを閉じるまで、アプリケーションの他の部分は操作できなくなります。
ダイアログを表示し、ユーザーの選択や入力を取得するには、ダイアログクラスのスタティックメソッド(クラスメソッド)やインスタンスメソッドを使用します。
QMessageBoxの例
情報メッセージボックスを表示する例です。
“`python
import sys
from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton, QVBoxLayout, QWidget, QMessageBox
class MessageBoxExample(QMainWindow):
def init(self):
super().init()
self.setWindowTitle(“MessageBox Example”)
self.setGeometry(100, 100, 300, 150)
layout = QVBoxLayout()
button = QPushButton("Show Info Message")
button.clicked.connect(self.show_info_message)
layout.addWidget(button)
central_widget = QWidget()
central_widget.setLayout(layout)
self.setCentralWidget(central_widget)
def show_info_message(self):
# QMessageBox.information(parent, title, text, buttons) の形式で静的に呼び出すことが多い
QMessageBox.information(self, "Information", "This is an information message.")
if name == “main“:
app = QApplication(sys.argv)
window = MessageBoxExample()
window.show()
sys.exit(app.exec())
“`
QMessageBoxには、information(), warning(), critical(), question(), about()といった便利なスタティックメソッドが用意されています。これらは引数として親ウィジェット、タイトル、本文、表示するボタンなどを指定できます。ユーザーがどのボタンをクリックしたかの結果も取得できます。
例: 確認ダイアログと結果の取得
“`python
def ask_question(self):
# QMessageBox.question(parent, title, text, buttons)
# buttons は QMessageBox.StandardButton 列挙体で指定 (例: Yes, No, Cancel)
# 返り値はユーザーがクリックしたボタンを示す StandardButton 列挙体の値
reply = QMessageBox.question(
self,
“Confirmation”,
“Do you want to proceed?”,
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No | QMessageBox.StandardButton.Cancel
)
if reply == QMessageBox.StandardButton.Yes:
print("User clicked Yes")
elif reply == QMessageBox.StandardButton.No:
print("User clicked No")
elif reply == QMessageBox.StandardButton.Cancel:
print("User clicked Cancel")
else:
print("Dialog closed without clicking any standard button")
“`
QFileDialogの例
ファイルを開くダイアログを表示し、選択されたファイルパスを取得する例です。
“`python
import sys
from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton, QVBoxLayout, QWidget, QFileDialog, QLabel
class FileDialogExample(QMainWindow):
def init(self):
super().init()
self.setWindowTitle(“FileDialog Example”)
self.setGeometry(100, 100, 400, 200)
layout = QVBoxLayout()
self.file_label = QLabel("Selected File: None")
layout.addWidget(self.file_label)
button = QPushButton("Open File")
button.clicked.connect(self.open_file_dialog)
layout.addWidget(button)
central_widget = QWidget()
central_widget.setLayout(layout)
self.setCentralWidget(central_widget)
def open_file_dialog(self):
# QFileDialog.getOpenFileName(parent, caption, directory, filter) の形式で静的に呼び出すことが多い
# 返り値は (選択されたファイルパスのタプル, 選択されたフィルタ)
file_name, _ = QFileDialog.getOpenFileName(
self, # 親ウィジェット
"Open Text File", # ダイアログのタイトル
".", # 初期ディレクトリ (".": 現在のディレクトリ)
"Text Files (*.txt);;All Files (*)" # ファイルフィルタ (セミコロンで複数指定)
)
if file_name: # ファイルが選択された場合 (キャンセルされていない)
print(f"Selected file: {file_name}")
self.file_label.setText(f"Selected File: {file_name}")
else:
print("File selection cancelled")
self.file_label.setText("Selected File: None")
if name == “main“:
app = QApplication(sys.argv)
window = FileDialogExample()
window.show()
sys.exit(app.exec())
“`
QFileDialog.getOpenFileName()メソッドは、ファイルを開くダイアログを表示し、ユーザーが選択したファイルパスと、選択したフィルタをタプルで返します。ユーザーがキャンセルした場合は、ファイルパスは空の文字列になります。
同様に、getSaveFileName()メソッドでファイルを保存するダイアログ、getExistingDirectory()メソッドでディレクトリを選択するダイアログを表示できます。
これらの標準ダイアログは、ユーザーエクスペリエンスを向上させ、ファイル操作やユーザーへの情報提供を効率的に行うために不可欠です。
アプリケーションの配布
作成したPySide6アプリケーションを他のユーザーに使ってもらうためには、Pythonの実行環境がない環境でも動作する単一の実行可能ファイル(.exe, .appなど)としてパッケージング(配布可能な形式にまとめる)するのが便利です。
Pythonスクリプトをスタンドアロンの実行可能ファイルに変換するためのツールはいくつかありますが、PySide6アプリケーションのパッケージングによく使われるのはPyInstallerです。
PyInstallerを使った実行可能ファイル化
PyInstallerは、Pythonスクリプトとその依存ライブラリをまとめて、OSネイティブな実行可能ファイルを作成するツールです。
-
PyInstallerのインストール:
仮想環境をアクティベートした状態で、pipを使ってPyInstallerをインストールします。
bash
pip install pyinstaller -
アプリケーションのパッケージング:
アプリケーションのメインとなるPythonスクリプトファイル(例:app.py)があるディレクトリで、ターミナルを開き、以下のコマンドを実行します。
bash
pyinstaller app.py
このコマンドは、デフォルトではdistというディレクトリを作成し、その中にアプリケーションを実行するための複数のファイルとディレクトリを生成します。もし、依存ファイル(画像ファイル、データファイルなど)がある場合は、それらも一緒にパッケージングされるように指定する必要があります。また、PySide6のような複雑なライブラリの場合、追加の設定が必要になることもありますが、PyInstallerはQt/PySide6をある程度自動で検出してくれます。
-
単一ファイルとしてパッケージング (
--onefile):
配布が最も簡単なのは、依存ファイルも含めて一つの実行可能ファイルにまとめる方法です。これには--onefileオプションを使用します。
bash
pyinstaller --onefile app.py
このコマンドを実行すると、distディレクトリ内に単一の実行可能ファイルが生成されます(Windowsならapp.exe、macOSならapp、Linuxならappのような名前)。このファイルをコピーして他の環境で実行できます。注意:
--onefileオプションは便利ですが、アプリケーションの起動に時間がかかる場合があります。また、環境によっては依存関係の検出に失敗することがあります。 -
アイコンの設定 (
--icon):
実行可能ファイルにカスタムアイコンを設定するには、--iconオプションを使用します。アイコンファイルはICO形式(Windows)、ICNS形式(macOS)、PNG形式(Linux)など、OSによって適切な形式である必要があります。
bash
pyinstaller --onefile --icon=app.ico app.py
PyInstallerの実行後、生成されたdistディレクトリ内の実行可能ファイルを、パッケージング対象としたOSと同じOS上で実行してみてください。PySide6アプリケーションが起動すれば成功です。
PyInstallerは非常に多機能で、多くのオプションがあります。詳細はPyInstallerの公式ドキュメントを参照してください。大規模なアプリケーションや特殊な依存関係を持つアプリケーションの場合、.specファイルを編集してより詳細な設定を行う必要が出てくることもあります。
アプリケーションを配布する前に、必ずターゲットとするOSで正しく動作するかテストしてください。
PySide6開発のヒントとリソース
PySide6を使ったGUI開発は奥深く、この記事で紹介した内容はごく基本的な部分です。より高度な機能を使ったり、問題に直面したりしたときのために、開発に役立つヒントとリソースを紹介します。
Qtドキュメントの活用方法
PySide6はQtフレームワークのPythonバインディングです。したがって、PySide6のクラスやメソッドの多くは、C++版Qtのクラスやメソッドと1対1に対応しています。PySide6に関する情報が少ない場合でも、Qtの公式ドキュメント(C++版)が非常に参考になります。
- Qt 6 ドキュメント: https://doc.qt.io/qt-6/
- 各クラスの詳細な説明、メソッド、プロパティ、信号、スロットなどが記載されています。
- C++のコード例が多いですが、クラス名、メソッド名、信号・スロット名はPySide6でもほぼ同じです。C++のシグネチャをPySide6に読み替える練習をしましょう(例:
void clicked()はclicked信号、QString text()はtext()メソッド)。
- Qt for Python (PySide6) ドキュメント: https://doc.qt.io/qtforpython/
- PySide6固有の情報、インストール方法、基本的なチュートリアル、C++との対応関係などがあります。C++ドキュメントほど網羅的ではない場合がありますが、まずはここから始めるのが良いでしょう。
Qtのドキュメントは非常に詳細で網羅的ですが、最初は情報の多さに戸惑うかもしれません。特定のクラスやメソッドの使い方を知りたいときは、検索機能を活用するのが効果的です。
公式チュートリアル、サンプルコード
PySide6やQtの公式サイトでは、様々なチュートリアルやサンプルコードが提供されています。これらは実際のコードを見ながら学習するのに役立ちます。
- Qt for Pythonの公式ドキュメントには、いくつかの基本的なチュートリアルがあります。
- Qt Examples: Qtフレームワークの様々な機能をデモする豊富なサンプルコード集です。C++で書かれていることが多いですが、PySide6版のサンプルも提供されている場合があります。
コミュニティ、フォーラム
PySide6やQt開発で問題に直面した場合、コミュニティに助けを求めるのが有効です。
- Qt Forum: Qt開発全般に関する公式フォーラムです。PySide6に関する質問も歓迎されています。
- Stack Overflow:
pyside6やqt、pythonなどのタグを使って質問を検索したり、投稿したりできます。 - PythonやQt関連のDiscordサーバーやメーリングリストなど。
質問をする際は、使用しているPySide6のバージョン、Pythonのバージョン、OS、問題の具体的な状況、試したことなどを明確に記述すると、より適切な回答が得られやすくなります。
デバッグのヒント
GUIアプリケーションのデバッグは、CLIアプリケーションとは少し異なります。
- printデバッグ: 最もシンプルですが効果的な方法です。信号が期待通りに発信されているか、スロットが呼び出されているか、変数の値は何かなどを確認するために、スロット関数や他の処理の中に
print()文を挿入します。PySide6アプリケーションをターミナルから実行していれば、printの出力はターミナルに表示されます。 - IDEのデバッガー: VS CodeやPyCharmなどのIDEは、ブレークポイントを設定したり、ステップ実行したり、変数の値を調べたりできる強力なデバッガー機能を備えています。これらを活用することで、コードの実行フローやバグの原因を詳細に解析できます。
- Qtのエラーメッセージ: Qtは、UI構築やイベント処理に問題がある場合、コンソールにエラーメッセージや警告メッセージを出力することがあります。これらのメッセージはデバッグの重要な手がかりとなります。
- Qt Designerとの連携: レイアウトの問題など、UIに関する問題の場合は、Qt Designerでデザインを確認したり、Qt Designer上でレイアウトのプレビュー機能を使ったりすることも有効です。
まとめ
この記事では、PySide6を使った最初のPython GUIアプリケーションを作成するための基本的なステップと概念を詳細に解説しました。
- PySide6がQtフレームワークの強力な機能をPythonから利用できるライブラリであること
QApplicationによるアプリケーション管理、QWidgetによるウィンドウとウィジェット、そしてイベントループの基本構造QVBoxLayoutやQHBoxLayoutなどのレイアウトマネージャーを使った柔軟なウィジェット配置- GUIアプリケーションのイベント処理の核となる「信号とスロット」メカニズム
- GUIデザインを効率化するQt Designerの使い方と、
.uiファイルをPythonコードから利用する方法(特にpyside6-uicを使った変換とクラス継承の方法) QMessageBoxやQFileDialogといった標準ダイアログの利用- PyInstallerを使ったアプリケーションの配布方法
これらの知識があれば、PySide6を使ったシンプルなデスクトップアプリケーションを自分で開発できるようになっているはずです。
GUI開発は、テキストベースのプログラミングとは異なる考え方が必要になる部分もありますが、ユーザーが直接触れるインターフェースを自分の手で作る喜びは格別です。最初は戸惑うこともあるかもしれませんが、少しずつコードを書いて、実行して、試行錯誤を繰り返すことが上達への一番の近道です。
この記事で紹介した内容はPySide6のほんの一部に過ぎません。Qtフレームワークは、グラフィックス(QPainter, QGraphicsView)、データベース連携、ネットワーク、スレッド処理など、さらに多くの高度な機能を提供しています。興味を持った方は、ぜひQtの公式ドキュメントや他のリソースを参照して、さらに学習を進めてみてください。
この入門記事が、あなたのPySide6を使ったGUI開発の素晴らしい旅立ちの一助となれば幸いです。Happy Coding!