【初心者向け】PyQt5とは?Pythonで始めるGUI開発


【初心者向け】PyQt5とは?Pythonで始めるGUI開発

はじめに:プログラミングの次のステップ、GUI開発の世界へようこそ

プログラミング学習を進める中で、「自分で作ったプログラムを、もっと直感的に操作できるようにしたい」「コマンドを入力するだけでなく、ボタンをクリックしたり、文字を入力したりして動くアプリケーションを作りたい」と思ったことはありませんか?

まさにその願いを叶えるのが「GUI開発」です。GUI(Graphical User Interface)とは、私たちが普段コンピューターやスマートフォンの操作で見慣れている、ウィンドウ、ボタン、メニュー、アイコンなどの視覚的な要素を用いたインターフェースのことです。コマンドラインインターフェース(CLI)とは異なり、ユーザーはこれらの視覚要素を直接操作することで、プログラムと対話できます。

Pythonは、そのコードの書きやすさ、豊富なライブラリ、そして幅広い応用分野から、プログラミング初心者からプロまで多くの人々に愛されています。PythonでGUIアプリケーションを開発できれば、データ処理、自動化スクリプト、ネットワークアプリケーションなど、これまでPythonで培ってきたスキルを、よりユーザーフレンドリーな形で提供できるようになります。

PythonでGUI開発を行うためのライブラリはいくつか存在しますが、その中でも特に人気があり、高機能で、ビジネスレベルのアプリケーション開発にも耐えうるのが PyQt5 です。

PyQt5は、QtというC++で開発された強力なGUIフレームワークのPythonバインディング(PythonからQtの機能を使えるようにするライブラリ)です。Qtはその美しく、カスタマイズ可能なデザインと、Windows、macOS、Linuxといった主要なデスクトップOSはもちろん、組み込みシステムやモバイルプラットフォームにも対応できるクロスプラットフォーム性が最大の特長です。PyQt5を使うことで、Pythonの簡潔さを保ちつつ、Qtの持つ豊かな表現力と高いパフォーマンスを享受できます。

この記事では、プログラミング初心者の方や、GUI開発は初めてという方を対象に、PyQt5を使ったGUI開発の基本をゼロから詳細に解説します。

具体的には、

  • GUI開発の基本概念
  • PyQt5の開発環境の準備
  • PyQt5アプリケーションの基本的な構造
  • ウィンドウ、ボタン、テキストボックスなどの主要な部品(ウィジェット)の使い方
  • ウィジェットの配置を整えるレイアウト方法
  • ユーザーの操作(ボタンクリックなど)にプログラムが反応するための仕組み(シグナルとスロット)
  • GUIを視覚的にデザインできるQt Designerの使い方

などを学び、最終的には簡単なGUIアプリケーションを作成できるようになることを目指します。

さあ、PythonとPyQt5を使って、あなたのアイデアを「目に見える」アプリケーションとして形にする旅を始めましょう!

第1章:GUI開発の基本とPyQt5の立ち位置

GUI開発の世界に足を踏み入れる前に、基本的な概念と、Pythonエコシステムの中でPyQt5がどのような位置づけにあるのかを理解しておきましょう。

1.1 GUIとは? CLIとの比較

GUI(Graphical User Interface)は「グラフィカル・ユーザー・インターフェース」の略で、文字通り、グラフィカルな要素を使ってユーザーとコンピューターが対話するための仕組みです。私たちが普段使っているOSのデスクトップ画面、ウェブブラウザ、ワープロソフトなどは全てGUIアプリケーションです。

GUIの主な要素には以下のようなものがあります。

  • ウィンドウ(Window): アプリケーションの表示領域を区切る枠。
  • ウィジェット(Widget): ウィンドウの中に配置される、ボタン、テキストボックス、ラベル、チェックボックスなどの部品。コントロールとも呼ばれます。
  • メニュー(Menu): ファイル、編集、表示などの項目が並び、クリックすると様々な機能が選択できるもの。
  • アイコン(Icon): プログラムやファイルなどを視覚的に表現したもの。

これに対し、CLI(Command Line Interface)は「コマンド・ライン・インターフェース」の略で、キーボードを使ってコマンド(命令)を入力し、テキストで結果が表示される形式です。例えば、WindowsのコマンドプロンプトやPowerShell、macOS/Linuxのターミナルなどがこれにあたります。

CLIは慣れれば効率的で強力ですが、操作には特定のコマンドを覚える必要があり、初心者には敷居が高い場合があります。一方、GUIは視覚的に分かりやすく、直感的に操作できるため、多くの一般ユーザーにとって使いやすいインターフェースと言えます。

1.2 GUIアプリケーションの構成要素

ほとんどのGUIアプリケーションは、以下の3つの主要な要素で構成されています。

  1. ユーザーインターフェース (UI): ウィンドウやウィジェットなどの視覚的な要素そのものです。ユーザーはこれを見て、操作を行います。
  2. イベントハンドリング (Event Handling): ユーザーがUIに対して行った操作(マウスのクリック、キーボード入力、ウィンドウのサイズ変更など)を「イベント」と呼びます。イベントハンドリングは、これらのイベントを検知し、それに対してプログラムがどのように応答するかを定義する仕組みです。
  3. ビジネスロジック (Business Logic): アプリケーションの核となる、具体的な処理を行う部分です。例えば、計算、ファイル操作、データ処理など、ユーザーの要求に応じたタスクを実行します。イベントハンドリングによって呼び出され、UIを更新することもあります。

GUI開発では、これら3つの要素を組み合わせてアプリケーションを構築していきます。PyQt5は、UIの構築(ウィジェットやレイアウトの提供)とイベントハンドリングの仕組み(シグナル&スロット)を強力にサポートしてくれます。ビジネスロジックは、Pythonの通常のコーディングによって実装します。

1.3 PythonにおけるGUIフレームワークの種類

Pythonには、GUIアプリケーションを開発するためのライブラリ(フレームワークと呼ばれることもあります)がいくつか存在します。それぞれに特徴があり、開発の目的や好みに応じて選択されます。

  • Tkinter: Pythonの標準ライブラリに含まれており、別途インストールする必要がありません。シンプルで軽量ですが、提供されるウィジェットの種類が少なく、見た目のカスタマイズ性も限られます。簡単なツールや学習用途には十分ですが、本格的なアプリケーション開発には物足りない場合があります。
  • PyQt / PySide: QtフレームワークのPythonバインディングです。QtはAdobe PhotoshopやSkypeなど、多くの著名なアプリケーションで使用されている非常に高機能で成熟したGUIフレームワークです。
    • PyQt: Riverbank Computing社が提供。商用利用には有償ライセンスが必要(GPLv3ライセンスでも利用可能ですが、自身のコードもGPLv3にする必要があります)。古くからあり、情報が多いです。
    • PySide: Qt社自身が提供。LGPLライセンスなので、商用利用でも自身のコードを公開する義務はありません(ライブラリ自体への変更がない限り)。最近はPySide2/PySide6が主流になっており、PyQt5/PyQt6とAPIが非常に似ています。
    • この記事では特に指定がない限り PyQt5 を扱いますが、PySide2/PySide6でもほとんど同じコードで動作します。
  • Kivy: モバイル開発(iOS/Android)も視野に入れたモダンなフレームワークです。独自の描画エンジンを持ち、タッチ操作に適したUIを構築できます。デザイン性が高く、OpenGLを利用した描画も可能です。デスクトップアプリケーションも開発できますが、PyQt/PySideとは異なる設計思想を持ちます。
  • wxPython: ネイティブなGUIウィジェットを使用するため、そのOSの標準的な見た目や操作感に近いアプリケーションが開発できます。PyQt/PySideと同様に高機能ですが、情報量やコミュニティの規模はPyQt/PySideの方が大きい傾向があります。

1.4 なぜPyQt5を選ぶのか?

PythonでのGUI開発において、PyQt5(またはPySide)を選ぶことには多くのメリットがあります。

  • 高機能かつ豊富なウィジェット: Qtは非常に多くの種類のウィジェットを提供しており、複雑なGUIも構築可能です。データ表示用のテーブルやツリー、グラフ描画、OpenGL連携など、様々なニーズに対応できます。
  • 洗練されたデザインとカスタマイズ性: Qtは標準で提供されるウィジェットのデザインが美しく、またスタイルシート(CSSに似た記法)を使って見た目を詳細にカスタマイズできます。
  • クロスプラットフォーム: PyQt5で書いたコードは、Windows、macOS、Linuxなどの主要なデスクトップOSでほぼそのまま動作します。OSごとのGUIの違いを吸収してくれるため、異なるプラットフォーム向けにコードを書き直す必要がありません。
  • Qt Designerによる効率的なUI設計: 後述するQt Designerというツールを使うと、コードを書かずにドラッグ&ドロップ操作でGUIの画面レイアウトを設計できます。これにより、UI設計の効率が大幅に向上し、デザインとロジックを分離しやすくなります。
  • 活発なコミュニティと豊富な情報: PyQt/PySideは世界中で広く使われており、オンライン上に豊富なドキュメント、チュートリアル、Q&Aがあります。困ったときに解決策を見つけやすいのも大きなメリットです。
  • Pythonとの高い親和性: PyQt5はQtの機能をPythonのオブジェクトや構文に自然にマッピングしています。Pythonistaにとって直感的で学習しやすいAPI設計になっています。

デメリットとしては、Tkinterなどに比べるとライブラリの容量が大きく、インストールが必要です。また、PyQt5の商用利用には通常有償ライセンスが必要となる点が挙げられます(LGPLv3で公開されたソフトウェアや、GPLv3で公開する場合は無償利用可能)。ただし、個人学習やオープンソースプロジェクトであればGPLv3ライセンスで問題なく利用できる場合が多いです。もし商用利用でライセンスの制約を避けたい場合は、APIがほぼ同じであるPySide2/PySide6を選択するのも良いでしょう。この記事で学ぶ内容は、PySideでもそのまま応用できます。

1.5 Qtフレームワークについて

PyQt5は「Qt」という強力なC++製フレームワークのPythonバインディングです。PyQt5を使うということは、PythonからQtの持つ様々な機能を利用するということです。

Qtは、GUI開発だけでなく、ネットワーク通信、データベース連携、XML処理、マルチメディア、OpenGLを用いた3Dグラフィックス描画など、様々な機能を提供する包括的なフレームワークです。PyQt5を使うことで、これらのQtの機能をPythonのコードから簡単に呼び出すことができます。

PyQt5でGUIアプリケーションを作成する際には、内部的にはQtライブラリが動作しています。そのため、Qtの公式ドキュメントはPyQt5開発においても非常に参考になります(ただし、C++での記述をPythonに読み替える必要があります)。

第2章:PyQt5開発環境の準備

PyQt5を使ったGUI開発を始めるには、いくつかの準備が必要です。PythonのインストールからPyQt5ライブラリのインストール、そして便利なツールであるQt Designerの準備までを説明します。

2.1 Pythonのインストール

PyQt5はPythonライブラリなので、Pythonがコンピューターにインストールされている必要があります。ここではPython自体のインストール手順の詳細は割愛しますが、公式ウェブサイト (https://www.python.org/) から最新版のPython 3系をダウンロードしてインストールしておいてください。インストールの際に「Add Python to PATH」にチェックを入れるのを忘れないようにしましょう。

インストール後、コマンドプロンプトやターミナルを開き、以下のコマンドを実行してPythonが正しくインストールされ、PATHが通っているか確認できます。

“`bash
python –version

または

python3 –version
“`

バージョン情報が表示されればOKです。

2.2 仮想環境の推奨と作成方法

PyQt5のようなライブラリをインストールする際は、仮想環境 を使うことを強く推奨します。仮想環境とは、プロジェクトごとに独立したPythonの実行環境を作成する機能です。これにより、プロジェクトAで使うライブラリのバージョンと、プロジェクトBで使うライブラリのバージョンが異なっていても、互いに干渉することなく管理できます。システム全体のPython環境を汚染しないため、環境設定のトラブルを防ぐことができます。

Python 3.3以降では、標準ライブラリとして venv という仮想環境ツールが提供されています。これを使うのが最も簡単です。

まず、プロジェクトを作成したいディレクトリに移動します。

“`bash

例:デスクトップに ‘pyqt_project’ というフォルダを作成し移動

cd Desktop
mkdir pyqt_project
cd pyqt_project
“`

次に、そのディレクトリ内で以下のコマンドを実行して仮想環境を作成します。「.venv」は作成される仮想環境のフォルダ名で、慣習的に .venvenv が使われます。

bash
python -m venv .venv

このコマンドを実行すると、.venv というフォルダが作成され、その中にPythonの実行ファイルやpipなどがコピーされます。

仮想環境を作成したら、それを「アクティベート(有効化)」する必要があります。アクティベートすることで、以降のPythonやpipコマンドはその仮想環境内のものを使うようになります。

  • Windowsの場合:

    bash
    .venv\Scripts\activate

  • macOS/Linuxの場合:

    bash
    source .venv/bin/activate

アクティベートに成功すると、コマンドプロンプトやターミナルのプロンプトの先頭に (.venv) のような仮想環境名が表示されるようになります。

仮想環境を終了したい場合は、deactivate コマンドを実行します。

以降のライブラリインストールは、必ずこの仮想環境がアクティベートされた状態で行ってください。

2.3 PyQt5のインストール方法

仮想環境をアクティベートした状態で、以下のpipコマンドを実行してPyQt5をインストールします。

bash
pip install PyQt5 PyQt5-tools

  • PyQt5: PyQt5ライブラリ本体です。PythonコードからQtの機能を使うために必要です。
  • PyQt5-tools: PyQt5に関連する便利なツール群です。特に、GUIを視覚的に設計できる「Qt Designer」が含まれています。Qt Designerを使うために、このパッケージも一緒にインストールすることを強くお勧めします。

インストールが完了するまでしばらく待ちます。ネットワーク環境によっては時間がかかる場合があります。

インストール後、以下のコマンドでインストールされているパッケージを確認できます。PyQt5とPyQt5-toolsが表示されていれば成功です。

bash
pip list

2.4 Qt Designerのインストールと起動

PyQt5-tools をインストールしていれば、Qt Designerもインストールされています。Qt Designerは、GUI画面をコードで書くのではなく、視覚的にドラッグ&ドロップで配置できるツールです。初心者の方にとっては、まずQt Designerで画面を作ってみるのがおすすめです。

Qt Designerを起動するには、仮想環境がアクティベートされた状態で、以下のコマンドを実行します。

  • Windowsの場合:

    bash
    designer

  • macOS/Linuxの場合:

    • macOS: designer コマンドで起動しない場合があります。その場合は、.venv/bin または .venv/Library/bin ディレクトリ(仮想環境の場所による)を探し、designer 実行ファイルを見つけて直接起動します。例: ~/.venv/bin/designer
    • Linux: designer コマンドで起動できることが多いです。

Qt Designerが起動すると、最初に新しいフォーム(ウィンドウやダイアログなど)を作成するかどうかを尋ねるダイアログが表示されます。ここでは例えば「Main Window」を選択して「Create」ボタンをクリックすると、デザイン編集用のウィンドウが表示されます。

この章の後半でQt Designerを使ったGUI作成について詳しく解説しますが、ここでは起動できることを確認するだけでOKです。

2.5 簡単な動作確認

PyQt5が正しくインストールされたかを確認するために、Pythonインタープリタを起動して簡単なコードを実行してみましょう。仮想環境がアクティベートされた状態で、Python対話モードに入ります。

bash
python

対話モードに入ったら、以下のコードを入力してみます。

python
import PyQt5
print("PyQt5 installation confirmed!")

エラーが表示されず、「PyQt5 installation confirmed!」と表示されれば、PyQt5ライブラリはPythonからインポート可能な状態になっています。

これで、PyQt5を使ったGUI開発を始めるための環境構築は完了です。

第3章:PyQt5の基本構造と最小限のウィンドウ

PyQt5アプリケーションがどのように動作するのか、その基本的な構造を理解しましょう。そして、PyQt5を使って最小限のウィンドウを表示するコードを書いてみます。

3.1 PyQt5アプリケーションの基本的なテンプレートコード

ほとんどのPyQt5アプリケーションは、以下の要素を含む基本的なテンプレートコードから始まります。

“`python
import sys
from PyQt5.QtWidgets import QApplication, QWidget

1. QApplication オブジェクトを作成する

アプリケーション全体を管理する役割

app = QApplication(sys.argv)

2. ウィンドウ(または他のトップレベルウィジェット)を作成する

ここでは最も基本的な QWidget を使用

window = QWidget()

ウィンドウの設定(任意)

window.setWindowTitle(‘My First PyQt5 Window’) # ウィンドウタイトルを設定
window.setGeometry(100, 100, 400, 300) # ウィンドウの位置とサイズを設定 (x, y, width, height)

3. ウィンドウを表示する

window.show()

4. アプリケーションのイベントループを開始する

ユーザーの操作などを待ち受け、イベントが発生したらそれに応じた処理を実行する

sys.exit(app.exec_())
“`

この短いコード片の中に、PyQt5アプリケーションの核となる要素が詰まっています。それぞれの行が何をしているのか、順番に見ていきましょう。

3.2 QApplicationクラスの役割

“`python
import sys
from PyQt5.QtWidgets import QApplication, QWidget

app = QApplication(sys.argv)
“`

PyQt5アプリケーションを作成する上で、最初に必ず必要なのが QApplication クラスのインスタンスです。

  • QApplication は、GUIアプリケーション全体の実行を管理する重要なクラスです。
  • イベント処理(ユーザーの操作を検知する仕組み)の中核を担います。
  • アプリケーションの設定や、ウィンドウ間の連携、メインイベントループの管理など、多くの役割を持っています。
  • PyQt5アプリケーションには、必ず1つの QApplication インスタンスが必要です。

QApplication(sys.argv)sys.argv は、コマンドライン引数をPyQt5に渡すために使用されます。通常はそのまま記述しておけば問題ありません。

3.3 QWidgetクラス (基底ウィジェット)

“`python
window = QWidget()

window.setWindowTitle(‘My First PyQt5 Window’) # ウィンドウタイトルを設定
window.setGeometry(100, 100, 400, 300) # ウィンドウの位置とサイズを設定
“`

QWidget は、PyQt5における全てのユーザーインターフェース要素(ウィジェット)の基底クラスです。ボタン (QPushButton) やラベル (QLabel)、テキストボックス (QLineEdit) など、私たちが画面上に配置する全てのウィジェットは QWidget から派生しています。

QWidget 自体は、特に機能を持たない空の領域ですが、ウィンドウとして使用することもできます。上記のコードでは、この QWidget をトップレベルウィンドウとして使っています。

  • setWindowTitle('...'): ウィンドウのタイトルバーに表示されるテキストを設定します。
  • setGeometry(x, y, width, height): ウィンドウが表示される際のスクリーン上の位置 (x, y は左上隅の座標) と、ウィンドウの幅 (width) および高さ (height) を設定します。座標はスクリーンの左上を (0, 0) とします。

3.4 ウィンドウの表示

python
window.show()

ウィジェットを作成しただけでは、画面には表示されません。show() メソッドを呼び出すことで、そのウィジェット(ここではウィンドウとして使用している QWidget)が画面上に表示されます。

3.5 イベントループ (exec_())

python
sys.exit(app.exec_())

この行は、PyQt5アプリケーションの心臓部です。

  • app.exec_() (または app.exec() – Pythonの予約語 exec と衝突するため、PyQt5では通常 exec_ を使用します) は、アプリケーションのイベントループを開始します。
  • イベントループとは、プログラムがユーザーからのイベント(マウス操作、キーボード入力、ウィンドウのリサイズなど)をひたすら待ち続ける状態のことです。
  • イベントが発生すると、それに応じた処理(イベントハンドリング)が実行されます。
  • このイベントループが動作している間、GUIアプリケーションは応答可能になります。
  • ユーザーがウィンドウを閉じたりしてアプリケーションが終了すると、exec_() メソッドが終了コードを返します。
  • sys.exit() は、その終了コードを使ってプログラム全体を終了させます。

この行がないと、ウィンドウは一瞬表示されてすぐにプログラムが終了してしまい、ユーザーは何も操作できません。GUIアプリケーションがユーザーの操作を待つためには、必ずイベントループを開始する必要があります。

3.6 最小限のウィンドウを表示するコード

これまでの要素をまとめて、最小限のPyQt5ウィンドウを表示する完全なコードを以下に示します。

“`python
import sys
from PyQt5.QtWidgets import QApplication, QWidget

if name == ‘main‘:
# 1. アプリケーションオブジェクトを作成
app = QApplication(sys.argv)

# 2. QWidgetをインスタンス化(ウィンドウとして使用)
window = QWidget()

# ウィンドウの設定
window.setWindowTitle('Minimal PyQt5 Window')
window.setGeometry(300, 300, 250, 150) # x, y, width, height

# 3. ウィンドウを表示
window.show()

# 4. アプリケーションのイベントループを開始
# ウィンドウが閉じられるまでここで待機
sys.exit(app.exec_())

“`

コードの実行方法:

  1. 上記のコードを minimal_window.py のような名前でファイルに保存します。
  2. ターミナルまたはコマンドプロンプトを開き、そのファイルがあるディレクトリに移動します。
  3. 仮想環境をアクティベートします。 (例: Windowsなら .venv\Scripts\activate)
  4. 以下のコマンドでスクリプトを実行します。

    bash
    python minimal_window.py

正常に実行されると、指定した位置に、指定したタイトルとサイズの空のウィンドウが表示されます。ウィンドウを閉じると、プログラムが終了します。

if __name__ == '__main__': のブロックは、このスクリプトが直接実行された場合にのみブロック内のコードが実行されるようにするためのPythonの一般的な慣習です。他のスクリプトからモジュールとしてインポートされた場合には、このブロック内のコードは実行されません。GUIアプリケーションのエントリーポイントとしてよく使われます。

これで、PyQt5アプリケーションの最も基本的な骨組みを理解し、実行できるようになりました。次は、このウィンドウの中に様々な部品(ウィジェット)を配置する方法を学びます。

第4章:主要なウィジェットを使ってみる

PyQt5アプリケーションの画面は、様々な「ウィジェット」を組み合わせて作られます。ウィジェットはボタン、ラベル、テキストボックス、チェックボックスなど、ユーザーが見たり操作したりできる個々の部品です。この章では、よく使われるいくつかの主要なウィジェットの使い方を紹介します。

4.1 ウィジェットの基本的な使い方

すべてのウィジェットは QWidget から派生しており、共通の基本的な使い方があります。

  1. インスタンス化: 必要なウィジェットのクラスをインポートし、インスタンスを作成します。
  2. プロパティの設定: ウィジェットの見た目や初期値を設定します(例: テキスト、サイズ、有効/無効など)。
  3. 配置: ウィンドウや他のコンテナウィジェットの中に配置します。これは通常、レイアウトマネージャーを使うか、座標を指定して行います(レイアウトについては次の章で詳しく説明します)。
  4. 表示: 親ウィジェットが表示される際に一緒に表示されるか、または show() メソッドで明示的に表示します。

以下に、いくつかの主要なウィジェットとその簡単な使い方、よく使われるプロパティ/メソッドを示します。

4.2 QLabel (ラベル)

テキストや画像を表示するためのウィジェットです。ユーザーは操作できません。

“`python
from PyQt5.QtWidgets import QLabel

QLabelのインスタンスを作成

引数で初期テキストを指定可能

label = QLabel(‘Hello, PyQt5!’)

テキストを変更

label.setText(‘新しいテキスト’)

HTMLタグを使って装飾も可能

label.setText(‘

見出し

赤いテキスト

‘)

画像を表示(QPixmapを使う)

from PyQt5.QtGui import QPixmap

pixmap = QPixmap(‘path/to/image.png’)

label.setPixmap(pixmap)

テキストの配置を中央揃えにするなど

from PyQt5.QtCore import Qt

label.setAlignment(Qt.AlignCenter)

“`

  • QLabel(text, parent=None): ラベルを作成。初期テキストと親ウィジェットを指定。
  • setText(text): 表示するテキストを設定/変更。
  • text(): 現在表示されているテキストを取得。
  • setPixmap(pixmap): 表示する画像を QPixmap オブジェクトで設定。
  • setAlignment(alignment): テキストや画像の配置を設定 (Qt.AlignLeft, Qt.AlignRight, Qt.AlignCenterなど)。

4.3 QPushButton (ボタン)

ユーザーがクリックできるボタンです。最も基本的なインタラクティブウィジェットの一つです。

“`python
from PyQt5.QtWidgets import QPushButton

QPushButtonのインスタンスを作成

引数でボタンのラベルテキストを指定可能

button = QPushButton(‘Click Me’)

ボタンのテキストを変更

button.setText(‘新しいボタンテキスト’)

ボタンがクリックされたときの処理を設定(シグナル/スロット – 次の章で詳しく)

button.clicked.connect(some_function)

ボタンを無効化する

button.setEnabled(False)

“`

  • QPushButton(text, parent=None): ボタンを作成。初期テキストと親を指定。
  • setText(text): ボタンのラベルテキストを設定/変更。
  • text(): ボタンのラベルテキストを取得。
  • setEnabled(bool): ボタンの有効/無効を設定(無効なボタンはクリックできない)。
  • シグナル:
    • clicked: ボタンがクリックされたときに発信されるシグナル。

4.4 QLineEdit (一行テキスト入力)

ユーザーが一行のテキストを入力できるフィールドです。

“`python
from PyQt5.QtWidgets import QLineEdit

QLineEditのインスタンスを作成

line_edit = QLineEdit()

初期テキストを設定

line_edit.setText(‘ここにテキストを入力’)

入力されたテキストを取得

current_text = line_edit.text()

プレースホルダーテキスト(入力がないときに薄く表示されるテキスト)

line_edit.setPlaceholderText(‘入力してください…’)

テキストを読み取り専用にする

line_edit.setReadOnly(True)

入力モードを設定(例: パスワード入力のように文字を隠す)

line_edit.setEchoMode(QLineEdit.Password)

“`

  • QLineEdit(text="", parent=None): 一行テキスト入力フィールドを作成。初期テキストと親を指定。
  • setText(text): フィールドのテキストを設定/変更。
  • text(): 現在フィールドに入力されているテキストを取得。
  • setPlaceholderText(text): 入力がないときに表示される薄いテキストを設定。
  • setReadOnly(bool): 読み取り専用にするか設定。
  • setEchoMode(mode): 入力の表示方法を設定 (QLineEdit.Normal, QLineEdit.NoEcho, QLineEdit.Password, QLineEdit.PasswordEchoOnEdit)。
  • シグナル:
    • textChanged(text): フィールドのテキストが変更されるたびに発信。
    • returnPressed(): Enterキーが押されたときに発信。

4.5 QTextEdit (複数行テキスト入力)

ユーザーが複数行のテキストを入力できるフィールドです。リッチテキスト(太字、斜体など)も扱えます。

“`python
from PyQt5.QtWidgets import QTextEdit

QTextEditのインスタンスを作成

text_edit = QTextEdit()

初期テキストを設定(プレーンテキスト)

text_edit.setPlainText(‘これは複数行のテキストです。\n改行も含まれます。’)

初期テキストを設定(リッチテキスト)

text_edit.setHtml(‘

見出し

太字のテキスト

‘)

現在のテキストを取得(プレーンテキスト)

current_plain_text = text_edit.toPlainText()

現在のテキストを取得(HTML形式)

current_html_text = text_edit.toHtml()

テキストを追加

text_edit.append(‘新しい行’)

テキスト全体をクリア

text_edit.clear()

“`

  • QTextEdit(text="", parent=None): 複数行テキスト入力フィールドを作成。初期テキストと親を指定。
  • setPlainText(text): プレーンテキストを設定/変更。
  • toPlainText(): 現在のテキストをプレーンテキストで取得。
  • setHtml(html): リッチテキスト(HTML形式)を設定/変更。
  • toHtml(): 現在のテキストをHTML形式で取得。
  • append(text): テキストの最後に行を追加。
  • clear(): テキスト全体をクリア。
  • シグナル:
    • textChanged(): テキストが変更されるたびに発信。

4.6 QCheckBox (チェックボックス)

ON/OFFの状態を持つチェックボックスです。複数選択可能です。

“`python
from PyQt5.QtWidgets import QCheckBox

QCheckBoxのインスタンスを作成

checkbox = QCheckBox(‘オプション1’)

チェックボックスの状態を設定

checkbox.setChecked(True) # TrueでチェックON, FalseでOFF

チェックボックスの状態を取得

is_checked = checkbox.isChecked() # TrueまたはFalse

ラベルテキストを設定/変更

checkbox.setText(‘新しいオプション’)
“`

  • QCheckBox(text="", parent=None): チェックボックスを作成。ラベルテキストと親を指定。
  • setChecked(bool): チェックの状態を設定。
  • isChecked(): チェックの状態を取得。
  • setText(text): ラベルテキストを設定/変更。
  • シグナル:
    • stateChanged(state): チェックの状態が変更されたときに発信。stateQt.Checked (2), Qt.Unchecked (0), Qt.PartiallyChecked (1) のいずれか。
    • toggled(checked): チェックの状態が変更されたときに発信。checkedは bool 型 (TrueまたはFalse)。

4.7 QRadioButton (ラジオボタン)

複数の選択肢の中から一つだけを選択させるためのボタンです。通常、同じ親ウィジェット(または QButtonGroup)内のラジオボタンはグループ化され、一つを選択すると他の選択が解除されます。

“`python
from PyQt5.QtWidgets import QRadioButton, QWidget, QVBoxLayout, QApplication
import sys

アプリケーションとウィンドウの準備 (例)

app = QApplication(sys.argv)
window = QWidget()
layout = QVBoxLayout() # レイアウトを使って配置 (詳細は次章)
window.setLayout(layout)

ラジオボタンのインスタンスを作成

radio1 = QRadioButton(‘選択肢 A’)
radio2 = QRadioButton(‘選択肢 B’)
radio3 = QRadioButton(‘選択肢 C’)

レイアウトに追加 (例)

layout.addWidget(radio1)
layout.addWidget(radio2)
layout.addWidget(radio3)

初期選択状態を設定

radio2.setChecked(True)

どのボタンが選択されているか確認

if radio1.isChecked():
print(‘選択肢 A が選ばれています’)

ラジオボタンをグループ化したい場合 (同じ親に入れるか QButtonGroup を使う)

group = QButtonGroup(window)

group.addButton(radio1)

group.addButton(radio2)

group.addButton(radio3)

選択が変更されたときのシグナルは group.buttonClicked(id), group.idClicked(id) などを使用

“`

  • QRadioButton(text="", parent=None): ラジオボタンを作成。ラベルテキストと親を指定。
  • setChecked(bool): 選択状態を設定。通常、同じ親内の他のラジオボタンの選択を解除します。
  • isChecked(): 選択されているか取得。
  • setText(text): ラベルテキストを設定/変更。
  • シグナル:
    • toggled(checked): 選択状態が変更されたときに発信。checkedは bool 型 (TrueまたはFalse)。

4.8 QComboBox (コンボボックス – ドロップダウンリスト)

項目のリストから一つを選択するためのドロップダウンリストです。

“`python
from PyQt5.QtWidgets import QComboBox

QComboBoxのインスタンスを作成

combo_box = QComboBox()

項目を追加

combo_box.addItem(‘項目 1’) # 項目テキストのみ
combo_box.addItem(‘項目 2’, ‘item_data_2’) # 項目テキストとデータ
combo_box.addItems([‘項目 3’, ‘項目 4’]) # 複数の項目をリストで追加

現在選択されている項目のインデックスとテキストを取得

current_index = combo_box.currentIndex()
current_text = combo_box.currentText()

指定したインデックスの項目を選択状態にする

combo_box.setCurrentIndex(1) # 2番目の項目を選択 (インデックスは0から始まる)

指定したテキストの項目を選択状態にする

combo_box.setCurrentText(‘項目 3’)

指定したインデックスの項目に関連付けられたデータを取得

data = combo_box.itemData(current_index)

“`

  • QComboBox(parent=None): コンボボックスを作成。
  • addItem(text, userData=None): 項目を追加。関連データをオプションで指定可能。
  • addItems(texts): 複数の項目をリストで追加。
  • currentIndex(): 現在選択されている項目のインデックスを取得。
  • currentText(): 現在選択されている項目のテキストを取得。
  • setCurrentIndex(index): 指定したインデックスの項目を選択状態にする。
  • setCurrentText(text): 指定したテキストを持つ項目を選択状態にする。
  • itemText(index): 指定したインデックスの項目のテキストを取得。
  • itemData(index): 指定したインデックスの項目に関連付けられたデータを取得。
  • count(): 項目の数を取得。
  • シグナル:
    • currentIndexChanged(index): 選択された項目のインデックスが変更されたときに発信。
    • currentTextChanged(text): 選択された項目のテキストが変更されたときに発信。

4.9 QSlider (スライダー)

数値の範囲から値を選択するためのスライダーです。

“`python
from PyQt5.QtWidgets import QSlider
from PyQt5.QtCore import Qt

QSliderのインスタンスを作成

slider = QSlider(Qt.Horizontal) # スライダーの向きを指定 (Horizontal or Vertical)

最小値と最大値を設定

slider.setMinimum(0)
slider.setMaximum(100)

現在の値を設定

slider.setValue(50)

現在の値を取得

current_value = slider.value()

目盛りを表示する間隔を設定 (任意)

slider.setTickPosition(QSlider.TicksBothSides)
slider.setTickInterval(10)
“`

  • QSlider(orientation, parent=None): スライダーを作成。向き (Qt.Horizontal または Qt.Vertical) と親を指定。
  • setMinimum(value): 最小値を設定。
  • setMaximum(value): 最大値を設定。
  • setValue(value): 現在の値を設定。
  • value(): 現在の値を取得。
  • setTickPosition(position): 目盛りの表示位置を設定 (QSlider.NoTicks, QSlider.TicksAbove, QSlider.TicksBelow, QSlider.TicksBothSidesなど)。
  • setTickInterval(interval): 目盛りの表示間隔を設定。
  • シグナル:
    • valueChanged(value): スライダーの値が変更されるたびに発信。
    • sliderPressed(), sliderReleased(): スライダーが押された/離されたときに発信。

4.10 QProgressBar (プログレスバー)

処理の進行状況を表示するためのバーです。

“`python
from PyQt5.QtWidgets import QProgressBar

QProgressBarのインスタンスを作成

progress_bar = QProgressBar()

最小値と最大値を設定 (デフォルトは 0-100)

progress_bar.setMinimum(0)
progress_bar.setMaximum(100)

現在の値を設定

progress_bar.setValue(75) # 75%まで進行

現在の値を取得

current_value = progress_bar.value()

テキスト表示形式を設定 (例: %表示、現在の値/最大値など)

progress_bar.setFormat(‘%p%’) # %表示

progress_bar.setFormat(‘%v/%m’) # 現在値/最大値

“`

  • QProgressBar(parent=None): プログレスバーを作成。
  • setMinimum(value): 最小値を設定。
  • setMaximum(value): 最大値を設定。
  • setValue(value): 現在の値を設定。
  • value(): 現在の値を取得。
  • setFormat(format): 表示されるテキスト形式を設定。
  • setTextVisible(bool): テキストを表示するか設定。

4.11 その他の便利なウィジェット(紹介のみ)

  • QListWidget: 項目のリストを表示し、選択できるウィジェット。
  • QTableWidget: 表形式でデータを表示し、編集も可能なウィジェット。
  • QTreeWidget: ツリー構造で項目を表示するウィジェット。
  • QScrollArea: 内容が領域に収まらない場合にスクロールバーを追加するコンテナウィジェット。
  • QGroupBox: 関連するウィジェットをグループ化し、枠線とタイトルを付けるコンテナウィジェット。
  • QTabWidget: タブ形式で複数の画面を切り替えるコンテナウィジェット。

これらのウィジェットは、アプリケーションの目的に応じて使い分けます。まずは基本的なウィジェットの使い方をマスターし、必要に応じて他のウィジェットに挑戦していくのが良いでしょう。

これらのウィジェットは、作成しただけではウィンドウの左上隅に重なって表示されてしまいます。これらをきれいに配置するためには、「レイアウトマネージャー」という仕組みが必要です。次の章では、PyQt5の強力なレイアウトシステムについて学びます。

第5章:レイアウト管理

PyQt5アプリケーションの見た目を整える上で、ウィジェットをどのように配置するかは非常に重要です。手動で座標を指定して配置することも可能ですが(widget.move(x, y))、ウィンドウのサイズ変更に追随できなかったり、多数のウィジェットの管理が煩雑になったりします。

そこで活躍するのが「レイアウトマネージャー」です。レイアウトマネージャーを使うと、ウィジェット間の相対的な位置関係や伸縮性を定義するだけで、ウィンドウのサイズが変わってもウィジェットが適切に配置されるようになります。

5.1 なぜレイアウトが必要か

  • レスポンシブなUI: ウィンドウのサイズが変わっても、ウィジェットが適切な位置に配置され、必要に応じて伸縮します。
  • 簡単な管理: ウィジェットの正確なピクセル座標を計算する必要がなくなります。
  • クロスプラットフォーム対応: OSによってウィンドウの装飾やフォントサイズが異なることがありますが、レイアウトを使うことでこれらの違いを吸収しやすくなります。
  • 保守性の向上: UIの変更が容易になり、コードの見通しが良くなります。

PyQt5では、いくつかの標準的なレイアウトマネージャーが提供されており、これらを組み合わせて複雑なレイアウトを作成できます。レイアウトマネージャーは、ウィジェットをコンテナ(通常はウィンドウ自体や他のウィジェット)に追加し、そのコンテナの setLayout() メソッドに設定することで機能します。

5.2 基本的なレイアウトの種類

よく使われる基本的なレイアウトマネージャーは以下の3つです。

  • QVBoxLayout: ウィジェットを垂直方向(上から下へ)に一列に並べます。
  • QHBoxLayout: ウィジェットを水平方向(左から右へ)に一列に並べます。
  • QGridLayout: ウィジェットをグリッド(行と列)状に配置します。表形式のレイアウトに適しています。

これらのレイアウトは、他のレイアウトの中に配置する(ネストする)ことも可能です。例えば、水平レイアウトの中に垂直レイアウトを入れることで、より複雑なUI構造を表現できます。

5.3 ウィジェットをレイアウトに追加する方法

各レイアウトクラスには、ウィジェットや他のレイアウトを追加するためのメソッドがあります。

  • QVBoxLayout, QHBoxLayout: addWidget(widget, stretch=0, alignment=0), addLayout(layout, stretch=0), addStretch(stretch=0)
  • QGridLayout: addWidget(widget, row, column, rowSpan=1, columnSpan=1, alignment=0), addLayout(layout, row, column, rowSpan=1, columnSpan=1, alignment=0)

stretch 引数は、レイアウト内で利用可能な余分な空間がどのように分配されるかを制御します。値が大きいほど、そのウィジェット(またはレイアウト)がより多くの空間を占有しようとします。alignment 引数は、利用可能な領域内でのウィジェットの位置合わせを指定します(Qt.AlignLeft, Qt.AlignRight, Qt.AlignCenter, Qt.AlignTop, Qt.AlignBottomなど、フラグの組み合わせも可能)。

addStretch() は、空の伸縮可能なスペース(スペーサー)を追加します。これにより、ウィジェットを端に寄せたり、複数のウィジェット間に均等な空間を設けたりできます。

5.4 レイアウトを使ったコード例

最小限のウィンドウに、ラベルとボタンを垂直方向に配置してみましょう。

“`python
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QVBoxLayout

class MyWindow(QWidget):
def init(self):
super().init()
self.setWindowTitle(‘Layout Example’)
self.setGeometry(100, 100, 300, 200)

    # 垂直レイアウトのインスタンスを作成
    vbox_layout = QVBoxLayout()

    # ウィジェットを作成
    label = QLabel('これはラベルです')
    button = QPushButton('これはボタンです')

    # ウィジェットをレイアウトに追加
    vbox_layout.addWidget(label)
    vbox_layout.addWidget(button)

    # (オプション) レイアウトの上下に伸縮可能なスペースを追加
    vbox_layout.addStretch(1)

    # ウィンドウのメインレイアウトとして設定
    self.setLayout(vbox_layout)

if name == ‘main‘:
app = QApplication(sys.argv)
main_window = MyWindow()
main_window.show()
sys.exit(app.exec_())
“`

このコードを実行すると、ウィンドウの上部にラベル、その下にボタンが配置されます。ウィンドウのサイズを縦方向に変更すると、追加した addStretch(1) の部分が伸び縮みし、ラベルとボタンは上部に寄せられたままになります。もし addStretch() を追加しない場合、ラベルとボタンはウィンドウの中央付近に配置され、ウィンドウサイズ変更時にウィジェット間のスペースが調整されます。

次に、ラベル、入力フィールド、ボタンを水平方向に配置してみましょう。

“`python
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QLineEdit, QPushButton, QHBoxLayout

class MyWindow(QWidget):
def init(self):
super().init()
self.setWindowTitle(‘Horizontal Layout Example’)
self.setGeometry(100, 100, 400, 100)

    # 水平レイアウトのインスタンスを作成
    hbox_layout = QHBoxLayout()

    # ウィジェットを作成
    label = QLabel('名前:')
    line_edit = QLineEdit()
    button = QPushButton('OK')

    # ウィジェットをレイアウトに追加
    hbox_layout.addWidget(label)
    hbox_layout.addWidget(line_edit, 1) # line_editに伸縮性を与える
    hbox_layout.addWidget(button)

    # ウィンドウのメインレイアウトとして設定
    self.setLayout(hbox_layout)

if name == ‘main‘:
app = QApplication(sys.argv)
main_window = MyWindow()
main_window.show()
sys.exit(app.exec_())
“`

この例では、line_editaddWidget する際に stretch=1 を指定しています。これにより、ウィンドウのサイズを横方向に変更した際に、line_edit が余分な空間を占有して伸縮し、ラベルとボタンは固定幅のままになります。

5.5 QGridLayout (グリッドレイアウト)

グリッドレイアウトは、行と列を指定してウィジェットを配置します。電卓のキーパッドのようなレイアウトに適しています。

“`python
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QLineEdit, QPushButton, QGridLayout

class MyWindow(QWidget):
def init(self):
super().init()
self.setWindowTitle(‘Grid Layout Example’)
self.setGeometry(100, 100, 300, 150)

    # グリッドレイアウトのインスタンスを作成
    grid_layout = QGridLayout()

    # ウィジェットを作成
    label_name = QLabel('名前:')
    line_edit_name = QLineEdit()
    label_email = QLabel('メール:')
    line_edit_email = QLineEdit()
    button_send = QPushButton('送信')

    # ウィジェットをグリッドに追加 (行, 列, 縦結合数, 横結合数)
    grid_layout.addWidget(label_name, 0, 0)
    grid_layout.addWidget(line_edit_name, 0, 1)
    grid_layout.addWidget(label_email, 1, 0)
    grid_layout.addWidget(line_edit_email, 1, 1)
    grid_layout.addWidget(button_send, 2, 0, 1, 2) # 行2, 列0 に配置し、横2列を結合

    # ウィンドウのメインレイアウトとして設定
    self.setLayout(grid_layout)

if name == ‘main‘:
app = QApplication(sys.argv)
main_window = MyWindow()
main_window.show()
sys.exit(app.exec_())
“`

この例では、ラベルとテキストフィールドを2行2列のグリッドに配置し、ボタンを3行目の0列目に配置して横方向に2列分を結合(colspan=2)しています。これにより、ボタンが幅いっぱいに広がって表示されます。

5.6 ネストされたレイアウト

複雑なUIを作成するには、複数のレイアウトを組み合わせて使用します。あるレイアウトの中に別のレイアウトを追加することで、階層的な配置が可能です。

例えば、ウィンドウ全体は垂直レイアウトで、その中に配置する各セクションは水平レイアウトで要素を並べる、といった構造を作ることができます。

“`python
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QLineEdit, QPushButton, QVBoxLayout, QHBoxLayout

class MyWindow(QWidget):
def init(self):
super().init()
self.setWindowTitle(‘Nested Layout Example’)
self.setGeometry(100, 100, 400, 200)

    # メインの垂直レイアウト
    main_layout = QVBoxLayout()

    # 1行目の水平レイアウト
    hbox1 = QHBoxLayout()
    hbox1.addWidget(QLabel('名前:'))
    hbox1.addWidget(QLineEdit(), 1) # テキストフィールドに伸縮性

    # 2行目の水平レイアウト
    hbox2 = QHBoxLayout()
    hbox2.addWidget(QLabel('メール:'))
    hbox2.addWidget(QLineEdit(), 1) # テキストフィールドに伸縮性

    # 3行目の水平レイアウト (ボタンを右寄せにする例)
    hbox3 = QHBoxLayout()
    hbox3.addStretch(1) # 左側に伸縮可能なスペースを追加してボタンを右に押す
    hbox3.addWidget(QPushButton('キャンセル'))
    hbox3.addWidget(QPushButton('OK'))

    # メインレイアウトに水平レイアウトを追加
    main_layout.addLayout(hbox1)
    main_layout.addLayout(hbox2)
    main_layout.addLayout(hbox3)

    # ウィンドウのメインレイアウトとして設定
    self.setLayout(main_layout)

if name == ‘main‘:
app = QApplication(sys.argv)
main_window = MyWindow()
main_window.show()
sys.exit(app.exec_())
“`

この例では、垂直レイアウトの中に3つの水平レイアウトを配置しています。これにより、上下方向に並んだ各行の中で、要素が水平方向に並ぶ複雑なレイアウトを実現しています。3つ目の水平レイアウトでは addStretch(1) を使うことで、キャンセルボタンとOKボタンを右端に寄せています。

レイアウトマネージャーを使いこなすことで、ウィンドウサイズの変化にも対応できる、整然とした使いやすいGUIを効率的に作成できるようになります。レイアウトはGUI開発の非常に重要な要素なので、ここでしっかりと理解しておきましょう。

第6章:シグナルとスロット

PyQt5アプリケーションのGUIは、ユーザーの操作やシステムからの通知に対して動的に反応する必要があります。例えば、「ボタンがクリックされたら特定の関数を実行する」「テキストが入力されたら別のウィジェットを更新する」といった処理です。

PyQt5では、このようなイベント駆動型のプログラミングを実現するために「シグナルとスロット」という独自のメカニズムを使用します。これはQtフレームワークの中心的な概念であり、非常に強力です。

6.1 PyQt5におけるイベント処理の仕組み(シグナル/スロット)

  • シグナル (Signal): ある特定のイベントが発生したことを通知するものです。ウィジェットが何らかの状態変化やユーザー操作を受けたときに「発信」します。例えば、QPushButton はクリックされたときに clicked というシグナルを発信します。QLineEdit はテキストが変更されたときに textChanged というシグナルを発信します。
  • スロット (Slot): シグナルを受け取って実行される関数またはメソッドです。シグナルによってトリガーされる実際の処理を記述します。通常は、自分で定義したクラスのメソッドや、Pythonの通常の関数をスロットとして使用します。

シグナルとスロットは、connect() メソッドを使って「接続」することで関連付けられます。シグナルが発信されると、それに接続されているスロットが自動的に呼び出されます。この仕組みは、イベントの発生源(シグナル)と処理を行う側(スロット)を疎結合にするため、柔軟で再利用性の高いコードを記述できます。

6.2 シグナルとスロットの接続 (connect()メソッド)

シグナルとスロットを接続するには、シグナルオブジェクトの connect() メソッドを使います。

python
signal_object.connect(slot_function)

例:ボタンの clicked シグナルを、自分で定義した on_button_clicked という関数に接続する。

“`python
button = QPushButton(‘Click Me’)

def on_button_clicked():
print(“ボタンがクリックされました!”)

シグナルとスロットを接続

button.clicked.connect(on_button_clicked)
“`

このコードでは、button オブジェクトの clicked シグナルに、on_button_clicked 関数を接続しています。ボタンがクリックされると、自動的に on_button_clicked() 関数が実行され、「ボタンがクリックされました!」というメッセージがコンソールに表示されます。

6.3 よく使うシグナルの例と接続方法

いくつかの主要なウィジェットのシグナルと、それらをスロットに接続する例を見てみましょう。

例1: ボタンクリックでラベルのテキストを変更

“`python
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QVBoxLayout

class MyWindow(QWidget):
def init(self):
super().init()
self.setWindowTitle(‘Signal & Slot Example’)
self.setGeometry(100, 100, 300, 200)

    layout = QVBoxLayout()
    self.setLayout(layout)

    self.label = QLabel('初期テキスト') # QLabelをインスタンス変数として保持
    button = QPushButton('テキスト変更')

    layout.addWidget(self.label)
    layout.addWidget(button)

    # ボタンのclickedシグナルと、自身のメソッドを接続
    button.clicked.connect(self.update_label)

# シグナルによって呼び出されるメソッド(スロット)
def update_label(self):
    self.label.setText('ボタンがクリックされました!')
    print("update_labelメソッドが実行されました。")

if name == ‘main‘:
app = QApplication(sys.argv)
main_window = MyWindow()
main_window.show()
sys.exit(app.exec_())
“`

この例では、MyWindow クラスのメソッド update_label をスロットとして使用しています。メソッドはオブジェクトのインスタンス変数にアクセスできるため、ラベルのテキストを変更するといったGUIの状態を更新する処理を記述するのに便利です。

例2: QLineEditに入力されたテキストをリアルタイムで表示

QLineEdittextChanged(text) シグナルは、テキストが変更されるたびに入力された新しいテキストを引数としてスロットに渡します。

“`python
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QLineEdit, QVBoxLayout

class MyWindow(QWidget):
def init(self):
super().init()
self.setWindowTitle(‘Text Input Example’)
self.setGeometry(100, 100, 300, 150)

    layout = QVBoxLayout()
    self.setLayout(layout)

    self.line_edit = QLineEdit()
    self.display_label = QLabel('入力待ち...')

    layout.addWidget(QLabel('何か入力してください:'))
    layout.addWidget(self.line_edit)
    layout.addWidget(self.display_label)

    # QLineEditのtextChangedシグナルと、自身のメソッドを接続
    # シグナルから渡される引数(text)を、スロットの引数として受け取る
    self.line_edit.textChanged.connect(self.update_display_label)

# シグナルから渡されるテキストを受け取るスロット
def update_display_label(self, text):
    self.display_label.setText(f'現在の入力: {text}')
    # print(f"テキスト変更シグナル受信: {text}") # コンソールにも表示

if name == ‘main‘:
app = QApplication(sys.argv)
main_window = MyWindow()
main_window.show()
sys.exit(app.exec_())
“`

この例では、update_display_label メソッドが text という引数を受け取っています。これは textChanged シグナルが発信される際に、現在の QLineEdit の内容を自動的に渡してくれるためです。シグナルがどのような引数を渡すかは、PyQt5のドキュメントで確認できます。

6.4 ラムダ式を使った簡単なスロット

シグナルが発信されたときに、単純な一行の処理や、特定の引数を与えて関数を呼び出したい場合があります。そのような場合に、ラムダ式を使うと手軽に接続を記述できます。

“`python
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QLabel, QVBoxLayout

class MyWindow(QWidget):
def init(self):
super().init()
self.setWindowTitle(‘Lambda Slot Example’)
self.setGeometry(100, 100, 300, 200)

    layout = QVBoxLayout()
    self.setLayout(layout)

    self.click_count = 0 # クリックカウンター
    self.count_label = QLabel(f'クリック数: {self.click_count}')
    button = QPushButton('カウントアップ')

    layout.addWidget(self.count_label)
    layout.addWidget(button)

    # ボタンのclickedシグナルをラムダ式に接続
    # ラムダ式の中でインスタンスメソッドを呼び出す
    button.clicked.connect(lambda: self.increment_count())

    # 別例: ボタンクリックで常に同じテキストを設定
    # self.message_label = QLabel('待ち...')
    # layout.addWidget(self.message_label)
    # button_hello = QPushButton('Hello')
    # layout.addWidget(button_hello)
    # button_hello.clicked.connect(lambda: self.message_label.setText('Hello!'))

def increment_count(self):
    self.click_count += 1
    self.count_label.setText(f'クリック数: {self.click_count}')
    print(f"クリック数: {self.click_count}")

if name == ‘main‘:
app = QApplication(sys.argv)
main_window = MyWindow()
main_window.show()
sys.exit(app.exec_())
“`

ラムダ式 lambda: self.increment_count() は、「このラムダ式が実行されたら、self.increment_count() メソッドを呼び出す」という意味になります。clicked シグナル自体は引数を持ちませんが、もしシグナルが引数を持つ場合(例: textChanged(text))、ラムダ式の引数として受け取って利用することも可能です。

“`python

例: textChangedシグナルから渡されたテキストを別のラベルに表示

line_edit.textChanged.connect(lambda text: self.display_label.setText(f’入力中: {text}’))

“`

6.5 シグナルの切断 (disconnect())

一度接続したシグナルとスロットは、必要であれば切断することも可能です。

“`python

接続を保持しておく

connection = button.clicked.connect(self.on_button_clicked)

後で切断する

connection.disconnect() # PyQt5 >= 5.10

button.clicked.disconnect(self.on_button_clicked) # PyQt5 < 5.10 または接続オブジェクトを持っていない場合

“`

通常、アプリケーションの存続期間中はずっと接続しておけば問題ありませんが、特定の条件でのみ反応させたい場合などに切断/再接続が役立ちます。

シグナルとスロットのメカニズムは、PyQt5でインタラクティブなGUIアプリケーションを構築する上で不可欠です。最初は少し難しく感じるかもしれませんが、実際にコードを書いて試しながら慣れていきましょう。

第7章:Qt Designerを使ったGUI作成

PyQt5の強力な機能の一つに、GUIを視覚的にデザインできるQt Designerがあります。コードでウィジェットの配置やプロパティを設定するのは慣れるまで大変ですが、Qt Designerを使えばドラッグ&ドロップ操作で直感的にGUIを設計できます。

7.1 Qt Designerとは何か、メリット

Qt Designerは、Qtフレームワークの一部として提供されるWYSIWYG (What You See Is What You Get) エディタです。

メリット:

  • 直感的な操作: ウィジェットをツールボックスからドラッグしてフォームに配置し、サイズや位置、プロパティをマウス操作で設定できます。
  • レイアウトの視覚化: レイアウトマネージャーの効果をリアルタイムで確認しながら配置できます。
  • 効率化: UI設計のコードを手書きする手間を省けます。
  • デザインとロジックの分離: GUIの見た目(UI)を .ui というファイルに保存し、Pythonコードではその .ui ファイルを読み込んで利用します。これにより、UIのデザイン担当者とプログラミング担当者で作業を分担しやすくなります。
  • シグナル/スロットのプレビュー: Designer上で簡単なシグナル/スロット接続を設定し、動作をプレビューできます(ただし、複雑なロジックはPythonコードで実装が必要です)。

Designerで作成したUIは .ui というXML形式のファイルとして保存されます。この .ui ファイルをPythonコードから利用する方法はいくつかあります。

7.2 Qt Designerの基本的な使い方

Qt Designerを起動すると、まず新しいフォームの種類を選択するダイアログが表示されます。

  • Main Window: メニューバー、ツールバー、ステータスバーなどを持つ、典型的なアプリケーションウィンドウ。
  • Dialog: ポップアップメッセージや設定画面など、一時的なウィンドウ。
  • Widget: 他のウィンドウやレイアウトに埋め込んで使う、再利用可能なGUI部品。

ここでは「Main Window」を選択して作成を進めます。

Designerの画面は主に以下の領域に分かれています。

  • Tool Box: 利用可能なウィジェットの一覧。ここからフォームへドラッグ&ドロップして配置します。
  • Form Editor: 現在編集中のフォームが表示される領域。ウィジェットを配置したり、サイズや位置を調整したりします。
  • Object Inspector: フォーム上のウィジェットの階層構造を表示します。各ウィジェットはオブジェクト名(例: pushButton, label_2など)で識別されます。
  • Property Editor: 選択中のウィジェットの各種プロパティ(テキスト、サイズ、色、フォントなど)を表示・編集します。オブジェクト名もここで変更できます。
  • Signal & Slot Editor: シグナルとスロットの接続を視覚的に設定できます(コードで書くことが多いですが、Designerでも可能)。

簡単なUIを作成する手順:

  1. ウィジェットを配置: Tool Boxから必要なウィジェット(例: Label, Line Edit, Push Button)を選び、Form Editor上のフォームにドラッグ&ドロップします。
  2. ウィジェットのプロパティを設定: 配置したウィジェットを選択し、Property Editorでプロパティを変更します。
    • objectName: Pythonコードからウィジェットを参照する際に使う名前。分かりやすい名前(例: name_label, input_line_edit, greet_button)に変更することを推奨します。
    • text (Label, Button): 表示されるテキストを設定。
    • placeholderText (Line Edit): プレースホルダーテキストを設定。
    • サイズ、位置なども調整可能ですが、後述するレイアウトを使う方が通常は望ましいです。
  3. レイアウトを設定: フォーム上のウィジェットを選択するか、フォーム全体を選択した状態で、ツールバーや右クリックメニューからレイアウトを設定します。「Layout Vertically」「Layout Horizontally」「Layout in a Grid」などを選択します。ウィジェットがレイアウトボックス内に収まり、ウィンドウサイズ変更時に自動で調整されるようになります。複数のウィジェットを先に選択してからレイアウトを適用することもできます。
  4. ネストされたレイアウトの作成: 複数のウィジェットを選択して一つのレイアウトで囲み、そのレイアウトオブジェクト自体を別のレイアウトに追加することで、ネスト構造を作ります。例えば、ラベルと入力フィールドのペアを水平レイアウトで囲み、その水平レイアウトを垂直レイアウトに追加するといった具合です。
  5. プレビュー: フォームエディタの「フォーム」メニューから「プレビュー」を選択すると、作成したUIがどのように表示されるか確認できます。

7.3 .uiファイルの保存

デザインが完成したら、Designerの「ファイル」メニューから「保存」を選択し、.ui 拡張子でファイルに保存します(例: my_gui.ui)。この .ui ファイルには、配置されたウィジェットの種類、オブジェクト名、プロパティ、レイアウト情報などがXML形式で記述されています。

7.4 .uiファイルをPythonコードに変換する (pyuic5コマンド)

Designerで作成した .ui ファイルをPythonコードから利用するには、主に2つの方法があります。一つは、.ui ファイルを純粋なPythonコード(UIを構築するコード)に変換する方法です。

この変換には、PyQt5-tools と一緒にインストールされた pyuic5 というコマンドラインツールを使用します。仮想環境をアクティベートした状態で、ターミナルやコマンドプロンプトで以下のコマンドを実行します。

bash
pyuic5 -o my_gui_ui.py my_gui.ui

  • pyuic5: 変換ツール名。
  • -o my_gui_ui.py: 変換後のPythonコードを保存するファイル名を指定します。
  • my_gui.ui: 変換元の .ui ファイルを指定します。

このコマンドを実行すると、my_gui_ui.py というPythonファイルが生成されます。このファイルを開いてみると、Designerで配置したウィジェットを作成し、プロパティを設定し、レイアウトを適用するPythonコードが自動生成されていることがわかります。

生成されたPythonコードの使い方:

生成された my_gui_ui.py ファイルは、通常、UIをセットアップするためのクラスを含んでいます。このクラスを、自分で作成するアプリケーションのメインウィンドウクラスなどから継承するか、インスタンス化して使用します。

“`python
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow

pyuic5で生成されたファイルをインポート

from my_gui_ui import Ui_MainWindow # 生成されたファイルに含まれるクラス名

class MyMainWindow(QMainWindow):
def init(self):
super().init()

    # 生成されたUIクラスのインスタンスを作成
    self.ui = Ui_MainWindow()

    # UIをセットアップ (__init__ メソッド内で実行される)
    self.ui.setupUi(self)

    # Designerで設定したウィジェットにアクセス
    # 例: Designerでオブジェクト名を 'greetButton' としたボタン
    # self.ui.greetButton.clicked.connect(self.greet)

# def greet(self):
#     print("ボタンが押されました!")
    # 例: Designerでオブジェクト名を 'nameLineEdit' とした入力フィールドからテキストを取得
    # name = self.ui.nameLineEdit.text()
    # 例: Designerでオブジェクト名を 'messageLabel' としたラベルにテキストを設定
    # self.ui.messageLabel.setText(f"こんにちは、{name}さん!")

if name == ‘main‘:
app = QApplication(sys.argv)
main_window = MyMainWindow()
main_window.show()
sys.exit(app.exec_())
“`

この方法のメリットは、生成されたPythonファイルは純粋なPythonコードなので、他のPythonファイルと同じように扱えることです。デメリットは、UIを少し変更するたびに pyuic5 コマンドを再実行してファイルを更新する必要があることです。

7.5 .uiファイルをロードして利用する (loadUi関数)

.ui ファイルを変換せずに、実行時にPythonコードから直接読み込んで利用する方法もあります。このためには PyQt5.uic.loadUi 関数を使用します。この方法を使うには、PyQt5 ライブラリだけでなく PyQt5.uic もインストールされている必要がありますが、通常 PyQt5 と一緒に入手可能です。

“`python
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.uic import loadUi # loadUi関数をインポート

class MyMainWindow(QMainWindow):
def init(self):
super().init()

    # .uiファイルを直接ロード
    loadUi('my_gui.ui', self)

    # Designerで設定したウィジェットにアクセス
    # self.objectName で指定した名前でアクセス可能
    # 例: Designerでオブジェクト名を 'greetButton' としたボタン
    # self.greetButton.clicked.connect(self.greet)

# def greet(self):
#     print("ボタンが押されました!")
    # 例: Designerでオブジェクト名を 'nameLineEdit' とした入力フィールドからテキストを取得
    # name = self.nameLineEdit.text()
    # 例: Designerでオブジェクト名を 'messageLabel' としたラベルにテキストを設定
    # self.messageLabel.setText(f"こんにちは、{name}さん!")

if name == ‘main‘:
app = QApplication(sys.argv)
main_window = MyMainWindow()
main_window.show()
sys.exit(app.exec_())
“`

この方法のメリットは、UIを変更しても pyuic5 コマンドを実行し直す必要がないため、UIの調整が素早く行える点です。デメリットは、実行時に .ui ファイルが必要になることと、IDEによってはウィジェットのオブジェクト名に対するコード補完が効かない場合があることです。

初心者の方には、まず loadUi を使う方法が手軽でおすすめです。UIのデザインとPythonでのロジック記述を効率的に進められます。

どちらの方法を選ぶにしても、DesignerでUIを設計し、PythonコードでそのUIにロジック(シグナルとスロットの接続やその他の処理)を実装するという基本的なワークフローは同じです。

Designerを使いこなせるようになると、GUI開発の生産性が格段に向上します。ぜひ色々なウィジェットやレイアウトを試してみてください。

第8章:簡単なアプリケーションを作成してみよう(総合演習)

これまでに学んだ PyQT5 の基本要素(ウィジェット、レイアウト、シグナル/スロット)と Qt Designer の使い方を組み合わせて、簡単なアプリケーションを作成してみましょう。ここでは、テキスト入力とボタンを使って、入力されたメッセージを表示するシンプルなツールを作成します。

アプリケーションの仕様:

  • ウィンドウタイトル:「メッセージ表示ツール」
  • ウィジェット構成:
    • メッセージ入力用の QLineEdit
    • メッセージを表示するための QLabel
    • メッセージを更新するための QPushButton
  • レイアウト:ウィジェットを垂直方向に並べる。
  • 機能:
    • ボタンをクリックすると、QLineEdit の内容を取得し、QLabel に表示する。

このアプリケーションを、Qt Designer を使って UI を作成し、Python コードでロジックを実装する、という流れで作ります。

8.1 Qt DesignerでUIを作成する

  1. Qt Designerを起動します。
  2. 新しいフォームとして「Main Window」を選択し、「Create」をクリックします。
  3. フォームが表示されたら、以下のウィジェットを Tool Box からドラッグ&ドロップして配置します。
    • Line Edit: Tool Box の Input Widgets セクションにあります。
    • Label: Tool Box の Display Widgets セクションにあります。
    • Push Button: Tool Box の Buttons セクションにあります。
  4. 配置したウィジェットの オブジェクト名 を変更します。Object Inspector で各ウィジェットを選択し、Property Editor の objectName プロパティを変更します。
    • Line Edit -> messageLineEdit
    • Label -> displayLabel
    • Push Button -> updateButton
      分かりやすい名前を付けることで、後で Python コードから参照しやすくなります。
  5. ウィジェットの 初期プロパティ を設定します。
    • Label (displayLabel): text プロパティを「ここにメッセージが表示されます」などに変更します。
    • Push Button (updateButton): text プロパティを「表示」に変更します。
    • Line Edit (messageLineEdit): 必要に応じて placeholderText プロパティを「メッセージを入力…」などに設定します。
  6. レイアウトを設定します。
    • 配置した3つのウィジェット(Line Edit, Label, Button)を全て選択します。
    • フォーム上の任意の場所で右クリックし、「Layout」->「Layout Vertically」を選択します。3つのウィジェットが垂直レイアウト内に配置されます。
    • Main Window のフォームの背景部分をクリックして、フォーム全体を選択状態にします。
    • 右クリックし、「Layout」->「Layout Vertically」を選択します。これにより、先ほど作成した垂直レイアウトがウィンドウのメインレイアウトとして設定されます。ウィンドウのサイズを変更すると、内部のウィジェットも適切に配置が調整されるようになります。
  7. ウィンドウタイトル を設定します。Object Inspector で MainWindow (フォーム全体) を選択し、Property Editor の windowTitle プロパティを「メッセージ表示ツール」に変更します。
  8. 保存します。「ファイル」->「保存」を選択し、ファイル名を message_tool.ui として保存します。

これで UI デザインは完了です。Qt Designer は閉じて構いません。

8.2 Python コードでロジックを実装する (loadUi を使用)

Qt Designer で作成した message_tool.ui ファイルを、Python コードからロードして使用し、ボタンクリック時の処理を実装します。

仮想環境がアクティベートされたターミナルで、以下の Python コードを message_tool.py のようなファイル名で保存します。message_tool.ui と同じディレクトリに保存してください。

“`python
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.uic import loadUi # loadUi 関数をインポート

QMainWindow を継承したカスタムクラスを作成

class MessageTool(QMainWindow):
def init(self):
super().init()

    # Qt Designer で作成した .ui ファイルをロード
    # ファイル名は Designer で保存した名前に合わせる
    loadUi('message_tool.ui', self)

    # Designer で設定したウィジェットに、objectName でアクセスできる
    # 例: messageLineEdit, displayLabel, updateButton

    # シグナルとスロットを接続
    # updateButton がクリックされたら、update_message メソッドを実行
    self.updateButton.clicked.connect(self.update_message)

# updateButton の clicked シグナルに接続されるスロット
def update_message(self):
    # messageLineEdit からテキストを取得
    input_text = self.messageLineEdit.text()

    # displayLabel に取得したテキストを設定して表示を更新
    self.displayLabel.setText(input_text)

    print(f"メッセージ更新: {input_text}") # デバッグ用にコンソールにも表示

アプリケーションのエントリーポイント

if name == ‘main‘:
app = QApplication(sys.argv)

# カスタムウィンドウクラスのインスタンスを作成し表示
main_window = MessageTool()
main_window.show()

# アプリケーションのイベントループを開始
sys.exit(app.exec_())

“`

8.3 アプリケーションの実行

  1. 仮想環境をアクティベートします。
  2. message_tool.py ファイルがあるディレクトリに移動します。
  3. 以下のコマンドを実行します。

    bash
    python message_tool.py

アプリケーションウィンドウが表示されます。Line Edit に何かテキストを入力し、「表示」ボタンをクリックしてみてください。入力したテキストが下の Label に表示されれば成功です!

コードの解説:

  • from PyQt5.uic import loadUi: .ui ファイルをロードするために必要な関数をインポートしています。
  • class MessageTool(QMainWindow):: 標準の QMainWindow を継承して、独自のウィンドウクラスを作成しています。これにより、QMainWindow の機能(メニューバー、ツールバーなど)を利用できるだけでなく、独自の初期化処理やスロットメソッドを追加できます。
  • loadUi('message_tool.ui', self): Qt Designer で作成した message_tool.ui ファイルをロードし、その内容を self (つまり MessageTool のインスタンス、ウィンドウ自身) に適用します。これにより、.ui ファイルで設計したウィジェットがウィンドウ内に配置され、Designerで設定したオブジェクト名(messageLineEdit, displayLabel, updateButton など)が self の属性として利用可能になります。
  • self.updateButton.clicked.connect(self.update_message): updateButton というオブジェクト名を持つボタンの clicked シグナルを、このクラスの update_message メソッドに接続しています。ボタンがクリックされるたびに update_message メソッドが呼び出されます。
  • update_message(self):: ボタンクリック時に実行されるスロットメソッドです。
    • self.messageLineEdit.text(): messageLineEdit というオブジェクト名を持つ Line Edit から、現在のテキストを取得します。
    • self.displayLabel.setText(input_text): displayLabel というオブジェクト名を持つ Label に、取得したテキストを設定し、表示を更新します。

このように、Qt Designer で画面の見た目をデザインし、Python コードでシグナルとスロットを接続してウィジェットに機能を与えるという流れが、PyQt5 開発の典型的なワークフローです。

このシンプルな例を発展させて、複数の入力フィールドを追加したり、計算処理を実装したり、ファイル操作を追加したりすることで、より実用的なアプリケーションを作成していくことができます。

第9章:PyQt5の応用と発展

基本的なウィジェット、レイアウト、シグナル/スロット、Qt Designerの使い方をマスターしたら、PyQt5のより高度な機能や、実用的なアプリケーション開発に役立つテクニックに挑戦してみましょう。

9.1 ダイアログ (QMessageBox, QFileDialog など)

ダイアログは、ユーザーに一時的な情報を伝えたり、ユーザーから入力を求めたりするための小さなポップアップウィンドウです。PyQt5には、よく使うダイアログがいくつか用意されています。

  • QMessageBox: 情報、警告、エラー、質問などのメッセージを表示し、ユーザーにOK/Cancelなどのボタンで応答を求めるためのダイアログです。

    “`python
    from PyQt5.QtWidgets import QMessageBox

    情報メッセージ

    QMessageBox.information(self, ‘情報’, ‘処理が完了しました。’)

    警告メッセージ

    QMessageBox.warning(self, ‘警告’, ‘注意してください!’)

    エラーメッセージ

    QMessageBox.critical(self, ‘エラー’, ‘重大なエラーが発生しました。’)

    質問メッセージとユーザーの応答取得

    reply = QMessageBox.question(self, ‘質問’, ‘続行しますか?’,
    QMessageBox.Yes | QMessageBox.No, QMessageBox.No) # ボタンの種類とデフォルトボタンを指定

    if reply == QMessageBox.Yes:
    print(‘ユーザーは「はい」を選択しました’)
    else:
    print(‘ユーザーは「いいえ」を選択しました’)
    “`

  • QFileDialog: ファイルを開く/保存するための標準的なダイアログです。

    “`python
    from PyQt5.QtWidgets import QFileDialog

    ファイルを開くダイアログ

    getOpenFileName() は (ファイルパス, 選択されたフィルター) のタプルを返す

    選択されなかった場合は (空文字列, 空文字列)

    file_path, _ = QFileDialog.getOpenFileName(self, ‘ファイルを開く’, ”, # タイトル, 開始ディレクトリ, フィルター
    ‘テキストファイル (.txt);;Pythonファイル (.py);;すべてのファイル (.)’)

    if file_path:
    print(f’選択されたファイル: {file_path}’)
    # ファイルを読み込む処理などを記述

    ファイルを保存するダイアログ

    file_path, _ = QFileDialog.getSaveFileName(self, ‘ファイルを保存’, ”,
    ‘テキストファイル (.txt);;すべてのファイル (.*)’)

    if file_path:
    print(f’保存先に指定されたパス: {file_path}’)
    # ファイルを書き込む処理などを記述
    “`

  • QFontDialog: フォントを選択するためのダイアログ。

  • QColorDialog: 色を選択するためのダイアログ。

これらの標準ダイアログを使うことで、OSの標準的なUIに沿ったダイアログを簡単に表示できます。

9.2 メニューバー、ツールバー、ステータスバー

QMainWindow クラスは、メニューバー (QMenuBar)、ツールバー (QToolBar)、ステータスバー (QStatusBar) を持つアプリケーションフレームウィンドウを提供します。これらの要素は、Qt Designer でも追加・編集できますし、コードで作成することも可能です。

メニューバーとアクション:

メニューバーは、ファイル、編集、表示などのメニュー項目を持ち、各メニュー項目は「アクション (QAction)」に接続されます。アクションは、メニュー項目、ツールバーボタン、ショートカットキーなどを介してトリガーされる、アプリケーション内の特定の操作(例: ファイルを開く、コピー、貼り付け)を表します。

“`python
from PyQt5.QtWidgets import QMainWindow, QAction

class MyMainWindow(QMainWindow):
def init(self):
super().init()
self.setWindowTitle(‘Menu Bar Example’)

    # メニューバーを取得 (QMainWindowはデフォルトで持っている)
    menubar = self.menuBar()

    # 「ファイル」メニューを作成
    file_menu = menubar.addMenu('&File') # & をつけると Alt+F でアクセス可能に

    # アクションを作成
    new_action = QAction('&New', self) # & をつけると Alt+N でアクセス可能に
    new_action.setShortcut('Ctrl+N') # ショートカットキーを設定
    new_action.setStatusTip('新しいファイルを作成します') # ステータスバーに表示されるヒント
    new_action.triggered.connect(self.new_file) # triggered シグナルを接続

    exit_action = QAction('&Exit', self)
    exit_action.setShortcut('Ctrl+Q')
    exit_action.setStatusTip('アプリケーションを終了します')
    exit_action.triggered.connect(self.close) # QMainWindow の close() メソッドに接続

    # アクションを「ファイル」メニューに追加
    file_menu.addAction(new_action)
    file_menu.addSeparator() # 区切り線を追加
    file_menu.addAction(exit_action)

    # ... 他のメニューやウィジェットの追加 ...

def new_file(self):
    print("「新規作成」アクションがトリガーされました")
    # 新しいファイルを作成する処理などを記述

“`

ツールバー:

ツールバーは、よく使うアクションをボタンとして配置する領域です。アクションをツールバーに追加することで、メニューからだけでなくツールバーからも同じ機能を実行できるようになります。

“`python
from PyQt5.QtWidgets import QMainWindow, QToolBar, QAction
from PyQt5.QtGui import QIcon # アイコンを使う場合

class MyMainWindow(QMainWindow):
def init(self):
super().init()
self.setWindowTitle(‘Toolbar Example’)

    # メニューバーとアクションを作成 (上記コードと同様)
    # ... file_menu, new_action, exit_action などを作成 ...

    # ツールバーを作成
    toolbar = self.addToolBar('File Toolbar') # ツールバー名

    # アクションをツールバーに追加
    # アイコン付きのアクションを作成する場合は QIcon を使う
    # new_action_with_icon = QAction(QIcon('path/to/new_icon.png'), '&New', self)
    # new_action_with_icon.triggered.connect(self.new_file)
    # toolbar.addAction(new_action_with_icon)

    toolbar.addAction(new_action)
    toolbar.addAction(exit_action)

    # ... 他のウィジェットの追加 ...

def new_file(self):
    print("「新規作成」アクションがトリガーされました")

“`

ステータスバー:

ステータスバーは、ウィンドウの下部に表示され、アプリケーションの状態や短いメッセージ(例: アクションのヒント、処理の進捗状況)を表示するために使用されます。

“`python
from PyQt5.QtWidgets import QMainWindow, QLabel, QStatusBar

class MyMainWindow(QMainWindow):
def init(self):
super().init()
self.setWindowTitle(‘Status Bar Example’)

    # ステータスバーを取得 (QMainWindowはデフォルトで持っている)
    statusbar = self.statusBar()

    # ステータスバーに一時的なメッセージを表示
    statusbar.showMessage('アプリケーション起動中...', 3000) # メッセージ, 表示時間(ミリ秒)

    # ステータスバーに常時表示されるウィジェットを追加 (例: 進行状況など)
    # progress_bar = QProgressBar()
    # progress_bar.setMaximumWidth(100) # 幅を制限
    # statusbar.addPermanentWidget(progress_bar)

    # ステータスバーに一時表示用のウィジェットを追加 (例: エラー件数など)
    # error_count_label = QLabel("Errors: 0")
    # statusbar.addWidget(error_count_label)

    # ... 他のウィジェットやメニューバーの追加 ...

# 他の場所からステータスバーのメッセージを更新する場合
# def update_status(self, message):
#     self.statusBar().showMessage(message)

“`

メニューバー、ツールバー、ステータスバーは、より本格的なデスクトップアプリケーションの見た目と機能を提供するために不可欠な要素です。

9.3 ファイルI/Oとの連携

GUIアプリケーションは、ファイルを開いて内容を表示したり、編集した内容をファイルに保存したりすることがよくあります。PyQt5でファイルダイアログを使ってファイルパスを取得し、Pythonの標準的なファイル操作と組み合わせることで、簡単にファイルI/O機能を実装できます。

“`python
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QTextEdit, QAction, QFileDialog
from PyQt5.QtGui import QIcon # アイコンを使う場合

class TextEditor(QMainWindow):
def init(self):
super().init()
self.setWindowTitle(‘Simple Text Editor’)
self.setGeometry(100, 100, 600, 400)

    # 中央ウィジェットとしてQTextEditを使用
    self.text_edit = QTextEdit()
    self.setCentralWidget(self.text_edit) # QMainWindow の中央に配置

    self.create_actions()
    self.create_menus()
    self.create_toolbars()
    self.create_status_bar()

def create_actions(self):
    # 「開く」アクション
    self.open_action = QAction(QIcon('open.png'), '&Open...', self) # アイコン画像は適宜用意
    self.open_action.setShortcut('Ctrl+O')
    self.open_action.setStatusTip('ファイルを開く')
    self.open_action.triggered.connect(self.open_file)

    # 「保存」アクション
    self.save_action = QAction(QIcon('save.png'), '&Save', self) # アイコン画像は適宜用意
    self.save_action.setShortcut('Ctrl+S')
    self.save_action.setStatusTip('ファイルを保存')
    self.save_action.triggered.connect(self.save_file)

    # 「終了」アクション
    self.exit_action = QAction(QIcon('exit.png'), '&Exit', self) # アイコン画像は適宜用意
    self.exit_action.setShortcut('Ctrl+Q')
    self.exit_action.setStatusTip('アプリケーションを終了')
    self.exit_action.triggered.connect(self.close)


def create_menus(self):
    menubar = self.menuBar()
    file_menu = menubar.addMenu('&File')
    file_menu.addAction(self.open_action)
    file_menu.addAction(self.save_action)
    file_menu.addSeparator()
    file_menu.addAction(self.exit_action)

def create_toolbars(self):
    toolbar = self.addToolBar('File')
    toolbar.addAction(self.open_action)
    toolbar.addAction(self.save_action)
    toolbar.addAction(self.exit_action)

def create_status_bar(self):
     self.statusBar().showMessage('準備完了', 5000)

def open_file(self):
    # ファイルを開くダイアログを表示
    file_path, _ = QFileDialog.getOpenFileName(self, 'ファイルを開く', '',
                                          'テキストファイル (*.txt);;すべてのファイル (*.*)')

    if file_path:
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()
                self.text_edit.setPlainText(content) # QTextEdit にファイル内容を表示
            self.statusBar().showMessage(f'{file_path} を開きました', 3000)
        except Exception as e:
            QMessageBox.critical(self, 'エラー', f'ファイルを開けませんでした:\n{e}')
            self.statusBar().showMessage('ファイルを開く際にエラーが発生しました', 3000)

def save_file(self):
    # ファイルを保存するダイアログを表示
    file_path, _ = QFileDialog.getSaveFileName(self, 'ファイルを保存', '',
                                          'テキストファイル (*.txt);;すべてのファイル (*.*)')

    if file_path:
        try:
            with open(file_path, 'w', encoding='utf-8') as f:
                content = self.text_edit.toPlainText() # QTextEdit の内容を取得
                f.write(content)
            self.statusBar().showMessage(f'{file_path} に保存しました', 3000)
        except Exception as e:
            QMessageBox.critical(self, 'エラー', f'ファイルを保存できませんでした:\n{e}')
            self.statusBar().showMessage('ファイルを保存する際にエラーが発生しました', 3000)

if name == ‘main‘:
app = QApplication(sys.argv)
editor = TextEditor()
editor.show()
sys.exit(app.exec_())
“`

この例では、QTextEdit を中央ウィジェットとして配置し、メニューバーとツールバーに「開く」「保存」「終了」アクションを追加しています。各アクションは、QFileDialog を使ってファイルパスを取得し、Python標準の open() 関数でファイルの内容を読み書きするメソッドに接続されています。エラー処理のために QMessageBox も使用しています。

9.4 スレッド処理(GUIフリーズを防ぐ)

GUIアプリケーションで時間のかかる処理(例: 大量のデータ処理、ネットワーク通信、重い計算)をメインスレッド(GUIが表示され、イベントループが動作しているスレッド)で実行すると、GUIが応答しなくなり、「フリーズ」したように見えてしまいます。

これを避けるためには、時間のかかる処理を別のスレッド(バックグラウンドスレッド)で実行する必要があります。PyQt5はスレッドを扱うためのクラス(QThread)を提供していますが、スレッド間でGUI要素に直接アクセスするのは避けるべきです。代わりに、バックグラウンドスレッドからメインスレッドに「シグナル」を送ることで、GUIの更新を安全に行います。

スレッド処理は少し高度なトピックですが、GUIアプリケーションで応答性を保つためには非常に重要です。PyQt5でのスレッド処理については、別途詳細な学習が必要です。

9.5 スタイルシート(CSSライクな見た目の変更)

PyQt5は、ウィジェットの見た目をCSS(Cascading Style Sheets)によく似た構文でカスタマイズできるスタイルシート機能を提供しています。これにより、アプリケーション全体のテーマを設定したり、特定のウィジェットのデザインを変更したりするのが容易になります。

“`python

アプリケーション全体にスタイルを適用

app.setStyleSheet(“””
QWidget {
font-family: “Arial”;
font-size: 14px;
}
QPushButton {
background-color: #4CAF50; //
color: white;
border-style: outset;
border-width: 2px;
border-radius: 10px;
border-color: beige;
padding: 6px;
}
QPushButton:pressed {
background-color: #367c39; / 濃い緑 /
}
QLabel {
color: navy;
font-weight: bold;
}
“””)

特定のウィジェットにスタイルを適用

my_button.setStyleSheet(“””

QPushButton {

color: red;

}

“””)

“`

スタイルシートを使うことで、アプリケーションの見た目を簡単に、そして柔軟に変更できます。

9.6 実行可能ファイル化

PyQt5アプリケーションを配布したい場合、Python環境がないユーザーでも実行できるように、単一の実行可能ファイル(.exe, .appなど)にまとめることが一般的です。これには PyInstaller や cx_Freeze といったツールがよく使われます。

これらのツールは、Pythonスクリプトとその依存ライブラリ(PyQt5なども含む)を一つにまとめて、実行可能な形式に変換します。

“`bash

PyInstaller のインストール (仮想環境にインストール推奨)

pip install pyinstaller

スクリプトを単一ファイルにまとめる (Windowsの場合)

pyinstaller –onefile your_script_name.py

アイコンを指定したり、コンソールウィンドウを非表示にしたりするオプションもある

pyinstaller –onefile –windowed –icon=your_icon.ico your_script_name.py

“`

実行可能ファイル化は、アプリケーション開発の最終段階で検討されることが多いです。

これらの応用的なトピックは、PyQt5でよりリッチで実用的なアプリケーションを開発する上で重要になってきます。まずは基本をしっかり学び、必要に応じてこれらの機能に挑戦していきましょう。

第10章:PyQt5開発におけるTipsと注意点

PyQt5を使った開発を進める上で役立つ情報や、注意すべき点をいくつかご紹介します。

10.1 公式ドキュメントの活用

PyQt5やQtの公式ドキュメントは、最も信頼できる情報源です。PyQt5のクラスやメソッドの詳しい使い方、シグナルの種類、プロパティの説明などは、ドキュメントに網羅されています。

  • PyQt5 Reference Guide (Riverbank Computing): https://www.riverbankcomputing.com/static/Docs/PyQt5/
    PyQt5のPython APIリファレンスです。クラス名やメソッド名から詳細な説明を調べられます。
  • Qt Documentation (Qt Company): https://doc.qt.io/qt-5/
    Qtフレームワーク自体のC++ドキュメントです。概念的な説明(例: レイアウトシステム、シグナル&スロットの仕組み)や、ウィジェットの機能について詳しく書かれています。PyQt5はこのQtの機能をPythonから呼び出しているだけなので、Qtドキュメントも大いに参考になりますが、C++のコード例をPythonに読み替える必要があります。

最初は難しく感じるかもしれませんが、何か機能を実現したいときや、エラーの原因が分からないときは、まずドキュメントを調べてみる習慣をつけましょう。

10.2 エラーメッセージの読み方

PyQt5開発でエラーに遭遇することは避けられません。Pythonの標準的なエラー(NameError, AttributeError, TypeErrorなど)に加えて、Qtライブラリ内部からのエラーや警告が表示されることもあります。

  • PythonのTraceback: エラーが発生したファイル名、行番号、エラーの種類、エラーメッセージなどが表示されます。一番下の行に表示されるエラーの種類とメッセージが最も重要です。その上のTracebackは、エラーが発生するまでにどのような関数が呼び出されたかの履歴を示しており、問題箇所を特定するのに役立ちます。
  • Qtからの警告/エラー: コンソールに QObject::connect: No such signal ... のようなメッセージが表示されることがあります。これはPyQt5ではなくQtライブラリが出力しているメッセージです。シグナルやスロットの接続に失敗した場合によく見られます。シグナルやスロットの名前、引数の型などが間違っていないか確認しましょう。

エラーメッセージを注意深く読み、何が問題なのか(変数名の間違い、引数の型の違い、メソッドの存在しない呼び出しなど)を理解しようと努めることが重要です。

10.3 デバッグ方法

問題の原因を特定するにはデバッグが必要です。

  • print() デバッグ: 最もシンプルですが効果的な方法です。コードの途中に print() 文を挿入して、変数の値や特定のコードが実行されているかを確認します。シグナルが正しく発信され、スロットが呼び出されているかを確認するのに役立ちます。
  • IDEのデバッガー: PyCharm, VS Codeなどの統合開発環境(IDE)には強力なデバッガー機能があります。ブレークポイントを設定してコードの実行を一時停止させたり、ステップ実行でコードを一行ずつ進めたり、その時点での変数の値を調べたりできます。本格的な開発にはIDEのデバッガーを使うのが最も効率的です。

10.4 ライセンスについて

PyQt5はデュアルライセンスです。

  • GPL (GNU General Public License) v3: GPLv3ライセンスでPyQt5を使用する場合、あなたの作成するアプリケーションのソースコードもGPLv3ライセンスで公開する必要があります。これはオープンソースプロジェクトや学習目的の場合に適しています。
  • 商用ライセンス: アプリケーションのソースコードを公開せずに商用利用したい場合は、Riverbank Computingから有償の商用ライセンスを購入する必要があります。

もしGPLv3ライセンスでの公開が難しい商用プロジェクトでPyQtを使用したい場合は、PyQtとほぼ同じAPIを持つ PySide2 または PySide6 を検討してください。PySideはLGPL(GNU Lesser General Public License)ライセンスで提供されており、自身のコードをGPLにする必要なく商用利用が可能です(ただし、PySideライブラリ自体への変更があった場合はその変更を公開する必要があります)。

個人学習やOSS開発の場合は、PyQt5をGPLv3ライセンスで使用することに問題はないでしょう。プロジェクトの目的や将来的な利用計画に応じて、ライセンスについて理解し、適切なライブラリを選択することが重要です。

10.5 PyQt vs PySide

前述したように、PyQtとPySideはどちらもQtフレームワークのPythonバインディングであり、非常に似たAPIを持っています。

  • PyQt5PySide2 がQt 5に対応するバージョンです。
  • PyQt6PySide6 がQt 6に対応するバージョンです。

機能的にはどちらも高機能ですが、以下のような違いがあります。

  • ライセンス: PyQtはGPL/商用、PySideはLGPL。これが最も大きな選択の決め手となることが多いです。
  • 開発元: PyQtはRiverbank Computing、PySideはQt Company。
  • APIの違い: 基本的には似ていますが、細かい部分(特にシグナルとスロットの接続構文など、過去のバージョンでは違いがあった)でわずかな違いがあります。PyQt5とPySide2、PyQt6とPySide6はAPIがかなり統一されてきています。
  • リリースサイクル: PyQtの方が新しいQtバージョンのバインディングが早くリリースされる傾向がありました。

学習目的であればどちらを選んでも構いません。PyQt5で学んだ知識は、PySide2/PySide6にほぼそのまま活かせます。商用利用を考えている場合は、LGPLライセンスのPySide系を選択するのが一般的です。

まとめ:PyQt5で広がるGUI開発の世界

この記事では、PyQt5を使ったPythonでのGUI開発について、その基本から応用までを詳細に解説しました。

GUI開発の必要性から始まり、PyQt5の環境構築、アプリケーションの基本構造、主要なウィジェットの使い方、レイアウトによる配置、シグナルとスロットによるイベント処理、そしてQt Designerによる効率的なUI設計の方法まで、PyQt5開発の主要な要素を網羅しました。さらに、ダイアログ、メニューバー、ファイルI/O連携といった応用的なトピックや、開発におけるTipsと注意点にも触れました。

PyQt5は、Pythonの学習曲線に沿いつつ、非常に強力で洗練されたGUIアプリケーションを開発できる素晴らしいライブラリです。Qt Designerを使うことで、プログラミングだけでなくデザインの側面からもGUI開発に取り組めるため、初心者の方でも視覚的な成果を早く得やすいというメリットがあります。

この記事を読んで、PyQt5を使ったGUI開発に興味を持ち、実際にコードを書いて動かす体験をしていただけたなら幸いです。

GUI開発の世界は奥深く、PyQt5にはここで紹介しきれなかった多くの機能があります。より複雑なウィジェット(グラフ表示、Webコンテンツ埋め込み、マップ表示など)、データベース連携、ネットワーク通信、OpenGL描画など、様々な機能をあなたのアプリケーションに追加できます。

今後の学習ステップ

  1. 基本的なアプリケーションを繰り返し作成: 学んだウィジェット、レイアウト、シグナル/スロットを組み合わせて、簡単なツールをいくつか作成してみましょう。電卓、ToDoリスト、ファイル操作ツールなど、身近なアイデアから始めてみるのが良いでしょう。
  2. Qt Designer をさらに使いこなす: より複雑なレイアウトや、ウィジェットのプロパティ設定を Designer で行う練習をしましょう。
  3. PyQt/Qt ドキュメントを参照する: 実現したい機能があれば、ドキュメントで関連するクラスやメソッドを探す練習をしましょう。
  4. 応用的なトピックに挑戦: 必要に応じて、ダイアログ、メニュー/ツールバー、スレッド処理、スタイルシートなどの応用機能に挑戦してみましょう。
  5. サンプルコードを読む: オープンソースのPyQt5アプリケーションや、オンラインで公開されているサンプルコードを読んでみるのも勉強になります。他の開発者がどのようにコードを書いているのかを学ぶことができます。

GUI開発は、あなたのアイデアをユーザーが直接触れて操作できる「形」にする、非常に創造的で楽しいプロセスです。PythonとPyQt5という強力なツールを手に入れたあなたは、様々なデスクトップアプリケーションを開発する可能性を秘めています。

さあ、学んだ知識を活かして、あなただけのGUIアプリケーションを創造しましょう!


コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール