9
Help us understand the problem. What are the problem?

posted at

updated at

【Python/GUI】PySide6のチュートリアル、作りました

はじめに

PythonのGUIライブラリの一つである「PySide6」の使い方について解説していきます。

これからPySide6を使っていこうと思っている方に向けて記載しております。
なるべく嚙み砕いて、それでいて簡潔にしたつもりです。

また、この記事ではよく使うであろうウィジェットに絞っております。
そのほか私が「おっこれいいなっ!」って思ったものがあれば、別の記事を記載して、そのリンクを貼っていきます。

環境

  • Windows 11 Home
  • Python 3
    • ここでは Python 3.9.9 を使用
  • テキストエディタ
    • 秀丸エディタ

PySide6って何ぞや?

世界で超絶大人気GUIライブラリの一つである「Qt」をPythonでも使えるようにしたのがPySide6です。

本来QtはC++で使用するものですが、あまりの人気っぷりにPythonでも使用できるようになりました。
いつからかは分かりませんが。

似たようなライブラリにPyQtってのがありますが、使える機能はほぼ同じです。
(全く同じかもしれません。PyQtは使ったことがないので分からないです)

PyQtに比べてPySideの方が「商用ライセンスがゆるい」ことが違いです。

ライセンス
PyQt: GPL
PySide: LGPL

ライセンスについては各自でググってください。
調べたことがないので、私には全く分かりません。

公式リファレンス

PySide6やQtの公式リファレンスです。
仲良くなりましょう!!

残念ながらPySide6のリファレンスは英語です。
日本語の文献は、Qiitaや個人ブログといったものになります。

海外ニキの作ったリファレンスを読めるように、がんばろうね。

開発環境の構築

PySide6のインストール

事前にPython3をインストールしてください。
Python3のインストール方法については、当ページでは省略します。

  • PowerShellを起動し、PySide6をインストールします。
pip install pyside6
  • 以下のプログラムを実行してウィンドウが表示できればインストール成功です。
# -*- encoding: shift-jis -*-
import PySide6
from PySide6 import QtCore
from PySide6 import QtWidgets
import os
import sys

# 環境変数にPySide6を登録
dirname = os.path.dirname(PySide6.__file__)
plugin_path = os.path.join(dirname, 'plugins', 'platforms')
os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = plugin_path

# とりあえずウィンドウと文字を表示
app = QtWidgets.QApplication()
label = QtWidgets.QLabel("こんにちは。", alignment=QtCore.Qt.AlignCenter)
label.setStyleSheet("font-size: 128px;")
label.show()
sys.exit(app.exec())

こんな感じになります。

000.png

本題の前に知っておきたい用語2選

これを知っておくとGUI開発をする上でちょこっとだけ理解しやすくなるキーワードを2つ選んでみました。
サクッと解説してみます。

ウィンドウ

ウェブブラウザやメモ帳などを起動したら、ディスプレイに表示される枠のことを「ウィンドウ」と言います。
百聞は一見に如かずってことで、見て理解しましょう。

word_000.png

ウィジェット

ウィンドウの中に表示されているもの全般のことを「ウィジェット」と言います。
ボタンや入力欄などの機能を持つものや、文字や画像などの情報のことを指します。

ザックリ言えば「クリックできるもの」や「見て分かるもの」のことです。
「見て分かるもの」という意味ではウィンドウもウィジェットの一部分になるんですかね?

word_001.png

PySide6の基本フォーマット

以下に示すプログラムを元に機能を追加して行きます。

このプログラムがPySide6の基本中の基本になります。
覚える必要はありませんが、いつでも引き出せるようにメモなどで保存するといいかと思います。

# -*- encoding: shift-jis -*-
import PySide6
from PySide6.QtWidgets import (QApplication,
                               QWidget)
import os
import sys


# PySide6のアプリ本体(ユーザがコーディングしていく部分)
class MainWindow(QWidget):              # ウィンドウ系クラスを継承すること
    def __init__(self, parent=None):    # parentは他にウィンドウを表示させる場合に指定する
        super().__init__(parent)        # 継承元クラス(ここではQWidget)を初期化


if __name__ == "__main__":
    # 環境変数にPySide6を登録
    dirname = os.path.dirname(PySide6.__file__)
    plugin_path = os.path.join(dirname, 'plugins', 'platforms')
    os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = plugin_path
    
    app = QApplication(sys.argv)    # PySide6の実行
    window = MainWindow()           # ユーザがコーディングしたクラス
    window.show()                   # PySide6のウィンドウを表示
    sys.exit(app.exec())            # PySide6の終了

ウィンドウ

アプリの基本中の基本です。
GUI開発はここからはじまります。

ウィンドウを表示する

まずはウィンドウを表示します。
そのコードがこちらです。

# -*- encoding: shift-jis -*-
import PySide6
from PySide6.QtWidgets import (QApplication,
                               QWidget)
import os
import sys


# PySide6のアプリ本体(ユーザがコーディングしていく部分)
class MainWindow(QWidget):
    def __init__(self, parent=None):
        # 親クラスの初期化
        super().__init__(parent)


if __name__ == "__main__":
    # 環境変数にPySide6を登録
    dirname = os.path.dirname(PySide6.__file__)
    plugin_path = os.path.join(dirname, 'plugins', 'platforms')
    os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = plugin_path
    
    app = QApplication(sys.argv)    # PySide6の実行
    window = MainWindow()           # ユーザがコーディングしたクラス
    window.show()                   # PySide6のウィンドウを表示
    sys.exit(app.exec())            # PySide6の終了

実行してみましょう。

window_000.png

ウィンドウが表示されましたね。
実はこのコードは「PySide6の基本フォーマット」のコードをそのまんま実行しただけになります。

ウィンドウタイトル

次にウィンドウにタイトルを与えてみます。
そのコードがこちらです。

# -*- encoding: shift-jis -*-
import PySide6
from PySide6.QtWidgets import (QApplication,
                               QWidget)
import os
import sys


# PySide6のアプリ本体(ユーザがコーディングしていく部分)
class MainWindow(QWidget):
    def __init__(self, parent=None):
        # 親クラスの初期化
        super().__init__(parent)
        
        # ウィンドウタイトル
        self.setWindowTitle("PySide6で作ったアプリです。")


if __name__ == "__main__":
    # 環境変数にPySide6を登録
    dirname = os.path.dirname(PySide6.__file__)
    plugin_path = os.path.join(dirname, 'plugins', 'platforms')
    os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = plugin_path
    
    app = QApplication(sys.argv)    # PySide6の実行
    window = MainWindow()           # ユーザがコーディングしたクラス
    window.show()                   # PySide6のウィンドウを表示
    sys.exit(app.exec())            # PySide6の終了

さぁ実行しましょう。

window_001.png

ウィンドウのサイズ

ウィンドウサイズを指定してみます。
プログラムはこちら。

# -*- encoding: shift-jis -*-
import PySide6
from PySide6.QtWidgets import (QApplication,
                               QWidget)
import os
import sys


# PySide6のアプリ本体(ユーザがコーディングしていく部分)
class MainWindow(QWidget):
    def __init__(self, parent=None):
        # 親クラスの初期化
        super().__init__(parent)
        
        # ウィンドウサイズを指定(px単位)
        windowWidth = 1000  # ウィンドウの横幅
        windowHeight = 800  # ウィンドウの高さ
        
        # ウィンドウサイズの変更
        self.resize(windowWidth, windowHeight)


if __name__ == "__main__":
    # 環境変数にPySide6を登録
    dirname = os.path.dirname(PySide6.__file__)
    plugin_path = os.path.join(dirname, 'plugins', 'platforms')
    os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = plugin_path
    
    app = QApplication(sys.argv)    # PySide6の実行
    window = MainWindow()           # ユーザがコーディングしたクラス
    window.show()                   # PySide6のウィンドウを表示
    sys.exit(app.exec())            # PySide6の終了

実行結果になります。

window_002.png

ウィンドウの起動位置とサイズ

ウィンドウの起動時にサイズだけでなく位置を指定することもできます。
そのプログラムを見ていきましょう。

# -*- encoding: shift-jis -*-
import PySide6
from PySide6.QtWidgets import (QApplication,
                               QWidget)
import os
import sys


# PySide6のアプリ本体(ユーザがコーディングしていく部分)
class MainWindow(QWidget):
    def __init__(self, parent=None):
        # 親クラスの初期化
        super().__init__(parent)
        
        # ウィンドウの位置とサイズを指定(px単位)
        xPos = 400  # x座標
        yPos = 500  # y座標
        windowWidth = 600   # ウィンドウの横幅
        windowHeight = 400  # ウィンドウの高さ
        
        # ウィンドウの位置とサイズの変更
        self.setGeometry(xPos, yPos, windowWidth, windowHeight)


if __name__ == "__main__":
    # 環境変数にPySide6を登録
    dirname = os.path.dirname(PySide6.__file__)
    plugin_path = os.path.join(dirname, 'plugins', 'platforms')
    os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = plugin_path
    
    app = QApplication(sys.argv)    # PySide6の実行
    window = MainWindow()           # ユーザがコーディングしたクラス
    window.show()                   # PySide6のウィンドウを表示
    sys.exit(app.exec())            # PySide6の終了

こんな感じになります。

window_003.png

固定されたウィンドウのサイズ

ウィンドウサイズを変えたくない時もあるかと思います。
プログラムで設定したウィンドウサイズに固定することもできます。

そのプログラムがこちら。

# -*- encoding: shift-jis -*-
import PySide6
from PySide6.QtWidgets import (QApplication,
                               QWidget)
import os
import sys


# PySide6のアプリ本体(ユーザがコーディングしていく部分)
class MainWindow(QWidget):
    def __init__(self, parent=None):
        # 親クラスの初期化
        super().__init__(parent)
        
        # ウィンドウサイズを指定(px単位)
        windowWidth = 500   # ウィンドウの横幅
        windowHeight = 200  # ウィンドウの高さ
        
        # ウィンドウサイズの固定
        self.setFixedSize(windowWidth, windowHeight)


if __name__ == "__main__":
    # 環境変数にPySide6を登録
    dirname = os.path.dirname(PySide6.__file__)
    plugin_path = os.path.join(dirname, 'plugins', 'platforms')
    os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = plugin_path
    
    app = QApplication(sys.argv)    # PySide6の実行
    window = MainWindow()           # ユーザがコーディングしたクラス
    window.show()                   # PySide6のウィンドウを表示
    sys.exit(app.exec())            # PySide6の終了

実行するとこうなります。

window_004.png

最大化はできなくなってますね。
画像だと分からないですが、四隅をマウスでサイズ変更できなくなっています。

【公式リファレンス】ウィンドウ

QWidget

ラベル

ラベルは情報を表示するのに使用しますが、このラベルという「意味」をちょこっとだけ詳しく説明します。

ラベルの意味について注意

TkinterやWindows FormsなどのGUI開発系の解説ページを見るとラベルは以下のような説明を見ます。


「文字」を表示するのにラベルを使用します。

ちょこっと説明が足りないかな・・・

実はこのラベル、文字だけじゃなくて画像や動画にも適用できるのです。
一言でまとめれば「ユーザにとって情報となるもの」がラベルです。

文字を表示する

まずはラベルを使って文字を表示してみます。
そのプログラムがこちらです。

# -*- encoding: shift-jis -*-
import PySide6
from PySide6.QtWidgets import (QApplication,
                               QLabel,          # ラベルを使うのに必要
                               QWidget)
import os
import sys


# PySide6のアプリ本体(ユーザがコーディングしていく部分)
class MainWindow(QWidget):
    def __init__(self, parent=None):
        # 親クラスの初期化
        super().__init__(parent)
        
        # ウィンドウタイトル
        self.setWindowTitle("PySide6で作ったアプリです。")
        
        # ラベルを表示するメソッド
        self.SetLabel()
        
    # ラベルは別のメソッドに分けました
    def SetLabel(self):
        # ラベルを使うことを宣言(引数のselfはウィンドウのことで、ウィンドウにラベルが表示されます)
        label = QLabel(self)
        
        # ラベルに文字を指定
        label.setText("こんにちは。ラベルです。")


if __name__ == "__main__":
    # 環境変数にPySide6を登録
    dirname = os.path.dirname(PySide6.__file__)
    plugin_path = os.path.join(dirname, 'plugins', 'platforms')
    os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = plugin_path
    
    app = QApplication(sys.argv)    # PySide6の実行
    window = MainWindow()           # ユーザがコーディングしたクラス
    window.show()                   # PySide6のウィンドウを表示
    sys.exit(app.exec())            # PySide6の終了

実行してみましょう。

label_000.png

ちゃんと指定した文字が表示されましたね。

文字サイズとかを変えてみる

先ほどのラベルだと文字が小さくて見にくかったですね。
大きさと色を変えてみましょう。

ちなみにサイズとかを変えるにはQt Style Sheetという技術を使います。

# -*- encoding: shift-jis -*-
import PySide6
import PySide6.QtGui
from PySide6.QtWidgets import (QApplication,
                               QLabel,          # ラベルを使うのに必要
                               QWidget)
import os
import sys


# PySide6のアプリ本体(ユーザがコーディングしていく部分)
class MainWindow(QWidget):
    def __init__(self, parent=None):
        # 親クラスの初期化
        super().__init__(parent)
        
        # ウィンドウタイトル
        self.setWindowTitle("PySide6で作ったアプリです。")
        
        # ラベルを表示するメソッド
        self.SetLabel()
        
    # ラベルは別のメソッドに分けました
    def SetLabel(self):
        # ラベルを使うことを宣言
        label = QLabel(self)
        
        # ラベルの見た目をQt Style Sheetで設定
        labelStyle = """QLabel {
            color:            #FF00AA;  /* 文字色 */
            font-size:        64px;     /* 文字サイズ */
            background-color: #FFAA00;  /* 背景色 */
        }"""
        
        # 見た目の設定をラベルに反映させる
        label.setStyleSheet(labelStyle)
        
        # ラベルに文字を指定
        label.setText("はぇ~、すっごい")


if __name__ == "__main__":
    # 環境変数にPySide6を登録
    dirname = os.path.dirname(PySide6.__file__)
    plugin_path = os.path.join(dirname, 'plugins', 'platforms')
    os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = plugin_path
    
    app = QApplication(sys.argv)    # PySide6の実行
    window = MainWindow()           # ユーザがコーディングしたクラス
    window.show()                   # PySide6のウィンドウを表示
    sys.exit(app.exec())            # PySide6の終了

結果はこんな感じです。

label_001.png

ラベルで画像を表示する

キュートな私のアイコンを表示してみたいと思います。
「Qt」なだけに(激うまギャグ)

紲星あかり.png

プログラムはこちらです。

# -*- encoding: shift-jis -*-
import PySide6
from PySide6.QtGui import (QPixmap) # Qtで画像を扱うのに必要
from PySide6.QtWidgets import (QApplication,
                               QLabel,          # ラベルを使うのに必要
                               QWidget)
import os
import sys


# PySide6のアプリ本体(ユーザがコーディングしていく部分)
class MainWindow(QWidget):
    def __init__(self, parent=None):
        # 親クラスの初期化
        super().__init__(parent)
        
        # ウィンドウタイトル
        self.setWindowTitle("PySide6で作ったアプリです。")
        
        # ラベルを表示するメソッド
        self.SetLabel()
        
    # ラベルは別のメソッドに分けました
    def SetLabel(self):
        # ラベルを使うことを宣言
        label = QLabel(self)
        
        # 画像の読み込み
        image = QPixmap(r".\img\紲星あかり.png")
        
        # 画像サイズの変更
        width = image.size().width() / 2    # 横幅を半分に
        height = image.size().height() / 2  # 高さを半分に
        image = image.scaled(width, height) # 読み込んだ画像のサイズを変更
        
        # ラベルに画像を指定
        label.setPixmap(image)


if __name__ == "__main__":
    # 環境変数にPySide6を登録
    dirname = os.path.dirname(PySide6.__file__)
    plugin_path = os.path.join(dirname, 'plugins', 'platforms')
    os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = plugin_path
    
    app = QApplication(sys.argv)    # PySide6の実行
    window = MainWindow()           # ユーザがコーディングしたクラス
    window.show()                   # PySide6のウィンドウを表示
    sys.exit(app.exec())            # PySide6の終了

実行したものがこちら。

label_002.png

【公式リファレンス】ラベル

QLabel

ボタン

ボタンを押した時と、離した時に何かを表示させてみたいと思います。
プログラムはこんな感じになります。

# -*- encoding: shift-jis -*-
import PySide6
from PySide6.QtWidgets import (QApplication,
                               QPushButton,     # ボタンを使うのに必要
                               QWidget)
import os
import sys


# PySide6のアプリ本体(ユーザがコーディングしていく部分)
class MainWindow(QWidget):
    def __init__(self, parent=None):
        # 親クラスの初期化
        super().__init__(parent)
        
        # ウィンドウタイトル
        self.setWindowTitle("PySide6で作ったアプリです。")
        
        # ボタンを表示するメソッド
        self.SetButton()
        
    # ボタンは別のメソッドに分けました
    def SetButton(self):
        # ボタンを使うことを宣言
        button = QPushButton(self)
        
        # ボタンに表示する文字
        button.setText("押してみよう!!")
        
        # ボタンを押したら実行させる処理
        # connectメソッド: 処理させるメソッド
        button.pressed.connect(self.CallbackButtonPressed)
        
        # ボタンを離したら実行させる処理(引数を指定する場合)
        # connectメソッド: 処理させるメソッド
        button.released.connect(lambda: self.CallbackButtonReleased(90))
        
    # ボタンが押されたら実行させるメソッド
    # connectメソッドから呼び出される
    def CallbackButtonPressed(self):
        print("やりますねぇ")
        
    # ボタンが離されたら実行させるメソッド(引数あり)
    # connectメソッドから呼び出される
    def CallbackButtonReleased(self, radian):
        print("横向くんだよ" + str(radian) + "度!")


if __name__ == "__main__":
    # 環境変数にPySide6を登録
    dirname = os.path.dirname(PySide6.__file__)
    plugin_path = os.path.join(dirname, 'plugins', 'platforms')
    os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = plugin_path
    
    app = QApplication(sys.argv)    # PySide6の実行
    window = MainWindow()           # ユーザがコーディングしたクラス
    window.show()                   # PySide6のウィンドウを表示
    sys.exit(app.exec())            # PySide6の終了

実行するとこんな感じになります。

button_000.gif

ちょっとだけ詳しく解説をば。
大事なところはこちら。

# ボタンを離したら実行させる処理(引数を指定する場合)
# connectメソッド: 処理させるメソッド
button.released.connect(lambda: self.CallbackButtonReleased(90))

引数ありの方で説明します。

buttonはQPushButtonクラスで宣言したボタンです。
問題は後ろのpressedreleasedconnectですね。

難しく考えないでください。
まずは構造を見てみましょう。

button_001.png

シグナルについて

ここではシグナルがpressedreleasedになります。
シグナルとは何ぞやってことですが、何かしらの操作があったら後ろのconnectメソッドで指定した処理を実行するよってなだけです。

ちなみにconnectメソッドで呼び出されるメソッドを「スロット」と言います。

ここで言えば、

  • マウスを押したらシグナルpressedが検知されてconnectメソッドでCallbackButtonPressedを実行
  • マウスを離したらシグナルreleasedが検知されてconnectメソッドでCallbackButtonReleasedを実行

しています。

button_002.png

ボタンに限らず他のウィジェットでもシグナルを持っており、何かしらの操作がされたらconnectメソッドで処理を呼び出すことができます。
これについては、各項目で説明していきますので、ご安心を。

ちなみにQPushButtonが持つシグナルは以下の通りです。

シグナル 機能
pressed 押したら実行
released 離したら実行
clicked クリックしたら実行(押して離したら)

connectメソッド

シグナルでも述べましたが、あるシグナル(ボタンを押したり話したり)があったらconnectメソッドで処理したいメソッドを呼び出します。

ですが注意が一つ。

引数を指定するには、無名関数 lambda で呼び出さないといけない

という鉄の掟があります。
見た方が分かりやすいと思いますので、引数を指定するのにイイ例とダメな例を書いてみます。

# ダメな引数の指定の仕方
button.released.connect(self.CallbackButtonReleased(90))

# イイ引数の指定の仕方
button.released.connect(lambda: self.CallbackButtonReleased(90))

引数を指定したい場合はlambdaでメソッドを呼び出さないとエラーになりますので、注意しましょう。

関数の引数に関数を、メソッドの引数にメソッドを指定することはGUI開発をする上でよくあることのようです。
私はエンジニアではないので全然分かりませんが、githubにアップされているプログラムを見ると「関数の引数に関数」「メソッドの引数にメソッド」を指定することは日常茶飯事です。

この引数に指定された関数・メソッドのことを「コールバック関数」と言います。
コールバック関数には名前のつけ方に決まり・・・というか慣習みたいなものがあるようで、以下のように命名されます。

(ex 1) 私はこっち派
Callback + ウィジェット名 + シグナル名
callback_widjet_signal(呼び出すメソッド名)
CallbackWidjetSignal(呼び出すメソッド名)

(ex 2)
ウィジェット名 + Callback
widjet_callback(呼び出すメソッド名)
WidgetCallback(呼び出すメソッド名)

【公式リファレンス】ボタン

QPushButton

先に絶対座標レイアウトだけ紹介しちゃいます

座標を指定せずに複数のウィジェットを追加すると上書きされちゃいます。
そこで絶対座標レイアウトでウィジェットを配置する方法をご紹介します。

絶対座標レイアウトとは(x, y)座標でウィジェットを配置するやり方です。
では見ていきましょう。

# -*- encoding: shift-jis -*-
import PySide6
from PySide6.QtWidgets import (QApplication,
                               QLabel,          # ラベルを使うのに必要
                               QPushButton,     # ボタンを使うのに必要
                               QWidget)
import os
import sys


# PySide6のアプリ本体(ユーザがコーディングしていく部分)
class MainWindow(QWidget):
    def __init__(self, parent=None):
        # 親クラスの初期化
        super().__init__(parent)
        
        # ウィンドウタイトル
        self.setWindowTitle("PySide6で作ったアプリです。")
        
        # ウィンドウサイズを指定(px単位)
        windowWidth = 300   # ウィンドウの横幅
        windowHeight = 200  # ウィンドウの高さ
        
        # ウィンドウサイズの変更
        self.resize(windowWidth, windowHeight)
        
        # ラベルを表示するメソッド
        self.SetLabel()
        
        # ボタンを表示するメソッド
        self.SetButton()
        
    # ラベルは別のメソッドに分けました
    def SetLabel(self):
        # ラベルを使うことを宣言
        lbl = QLabel(self)
        
        # ラベルに文字を指定
        lbl.setText("初代ポケモン四天王")
        
    # ボタンは別のメソッドに分けました
    def SetButton(self):
        # 各ボタンには何の機能も与えず、表示するだけ
        
        # 1つ目のボタン
        btn = QPushButton(self) # ボタンを使うことを宣言
        btn.setText("カンナ")   # とりあえずなんかしらの文字を表示
        btn.move(20, 25)        # ボタンの配置場所を絶対座標で指定
        
        # 2つ目のボタン
        btn = QPushButton(self) # ボタンを使うことを宣言
        btn.setText("ポッポ")   # とりあえずなんかしらの文字を表示
        btn.move(40, 50)        # ボタンの配置場所を絶対座標で指定
        
        # 3つ目のボタン
        btn = QPushButton(self) # ボタンを使うことを宣言
        btn.setText("キクコ")   # とりあえずなんかしらの文字を表示
        btn.move(60, 75)        # ボタンの配置場所を絶対座標で指定
        
        # 4つ目のボタン
        btn = QPushButton(self) # ボタンを使うことを宣言
        btn.setText("ワタル")   # とりあえずなんかしらの文字を表示
        btn.move(80, 100)       # ボタンの配置場所を絶対座標で指定


if __name__ == "__main__":
    # 環境変数にPySide6を登録
    dirname = os.path.dirname(PySide6.__file__)
    plugin_path = os.path.join(dirname, 'plugins', 'platforms')
    os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = plugin_path
    
    app = QApplication(sys.argv)    # PySide6の実行
    window = MainWindow()           # ユーザがコーディングしたクラス
    window.show()                   # PySide6のウィンドウを表示
    sys.exit(app.exec())            # PySide6の終了

実行するとちゃんと位置が変わっていることが分かります。

abpos_000.png

絶対座標によるレイアウトは分かりやすいのですが正直おススメしません。

い~っぱいウィジェットを配置しようとしたときに、全ウィジェットの(x, y)座標を指定しないといけなくなります。
もしウィジェットが100個もあったら、100個分もの(x, y)座標を1つずつ指定することになります。
恐ろしいですよね。

でも安心してください。
自動レイアウト機能もあります。

自動レイアウトに関しては別記事にする予定です。
現在執筆中です。

ラジオボタン

ラジオボタンを使えば、選択肢のいずれか一つだけ選べるナイスガイなウィジェットです。
ラジオボタンを使ったプログラムがこちらです。

ちょっと長いです。

# -*- encoding: shift-jis -*-
import PySide6
from PySide6.QtCore import (Qt)     # Qtの状態変数の取得に必要(ラジオボタンの入力状態の取得に使う)
from PySide6.QtGui import (QPixmap) # Qtで画像を扱うのに必要
from PySide6.QtWidgets import (QApplication,
                               QButtonGroup,    # ボタンをグループ化するのに必要
                               QLabel,          # ラベルを使う(画像を表示する)のに必要
                               QRadioButton,    # ラジオボタンを使うのに必要
                               QWidget)
import os
import sys


# PySide6のアプリ本体(ユーザがコーディングしていく部分)
class MainWindow(QWidget):
    def __init__(self, parent=None):
        # 親クラスの初期化
        super().__init__(parent)
        
        # ウィンドウタイトル
        self.setWindowTitle("PySide6で作ったアプリです。")
        
        # ラジオボタンを表示するメソッド
        self.SetRadio()
        
        # ラベルを表示するメソッド
        self.SetLabel()
        
    # ラジオボタンは別のメソッドに分けました
    def SetRadio(self):
        # ボタン系ウィジェットをグループ化する
        self.radioGroup = QButtonGroup(self)
        
        # 1つ目のラジオボタン
        self.radio1Id = 1                       # 1つ目のラジオボタンID
        radio1 = QRadioButton(self)             # ラジオボタンを使うことを宣言
        radio1.setText("のどがからっから")      # ラジオボタンに表示する文字
        radio1.move(10, 10)                     # ラジオボタンの表示位置を絶対座標で指定
        self.radioGroup.addButton(radio1, self.radio1Id)    # グループに登録
        
        # 2つ目のラジオボタン
        self.radio2Id = 2                       # 2つ目のラジオボタンのID
        radio2 = QRadioButton(self)             # ラジオボタンを使うことを宣言
        radio2.setText("おぉいしぃ")            # ラジオボタンに表示する文字
        radio2.move(10, 35)                     # ラジオボタンの表示位置を絶対座標で指定
        self.radioGroup.addButton(radio2, self.radio2Id)    # グループに登録
        
        # 3つ目のラジオボタン
        self.radio3Id = 3                       # 3つ目のラジオボタンID
        radio3 = QRadioButton(self)             # ラジオボタンを使うことを宣言
        radio3.setText("ス●ンジ・ボブだよ")    # ラジオボタンに表示する文字
        radio3.move(10, 60)                     # ラジオボタンの表示位置を絶対座標で指定
        self.radioGroup.addButton(radio3, self.radio3Id)    # グループに登録
        
        # 1つ目のラジオボタンを初期入力状態にする
        radio1.setChecked(True)
        
        # いずれかのラジオボタンがクリックされたら実行させる処理
        self.radioGroup.buttonClicked.connect(self.CallbackRadioStatechanged)
        
    # ラベルは別のメソッドに分けました
    def SetLabel(self):
        label = QLabel(self)    # ラベルを使うことを宣言
        xPos = 0                # ラベルのx座標
        yPos = 100              # ラベルのy座標
        label.move(xPos, yPos)  # ラベルの表示位置を指定
        image = QPixmap(r".\img\radio_000.png") # 画像読み込み
        
        # ウィンドウサイズを画像サイズに合わせる
        imageWidth = image.size().width() + xPos    # ウィンドウの横幅
        imageHeight = image.size().height() + yPos  # ウィンドウの高さ
        self.resize(imageWidth, imageHeight)        # ウィンドウサイズの更新
        
        # 画像表示
        label.setPixmap(image)
        
        # ふきだし画像
        self.commentLabel = QLabel(self)    # ラベルを使うことを宣言
        commentXPos = 200                   # ふきだし画像の初期x座標
        commentYPos = 600                   # ふきだし画像の初期y座標
        self.commentLabel.move(commentXPos, commentYPos)    # ふきだし画像の初期位置
        self.commentImage = QPixmap(r".\img\radio_001.png") # 初期のふきだし画像読み込み
        self.commentLabel.setPixmap(self.commentImage)      # 初期のふきだし画像の表示
        
    # ラジオボタンをクリックされたら実行されるメソッド
    def CallbackRadioStatechanged(self):
        # 1つ目のラジオボタンを選択したとき(checkedIdメソッドで選択中のボタンIDを取得)
        if self.radioGroup.checkedId() == self.radio1Id:
            self.commentImage = QPixmap(r".\img\radio_001.png") # ふきだし画像読み込み
            commentXPos = 200   # ふきだし画像の表示x座標
            commentYPos = 600   # ふきだし画像の表示y座標
        # 2つ目のラジオボタンを選択したとき(checkedIdメソッドで選択中のボタンIDを取得)
        elif self.radioGroup.checkedId() == self.radio2Id:
            self.commentImage = QPixmap(r".\img\radio_002.png") # ふきだし画像読み込み
            commentXPos = 0     # ふきだし画像の表示x座標
            commentYPos = 500   # ふきだし画像の表示y座標
        # 3つ目のラジオボタンを選択したとき(checkedIdメソッドで選択中のボタンIDを取得)
        elif self.radioGroup.checkedId() == self.radio3Id:
            self.commentImage = QPixmap(r".\img\radio_003.png") # ふきだし画像読み込み
            commentXPos = 600   # ふきだし画像の表示x座標
            commentYPos = 100   # ふきだし画像の表示y座標
        
        # ふきだし画像の移動
        self.commentLabel.move(commentXPos, commentYPos)
        
        # ふきだし画像を更新する
        self.commentLabel.setPixmap(self.commentImage)


if __name__ == "__main__":
    # 環境変数にPySide6を登録
    dirname = os.path.dirname(PySide6.__file__)
    plugin_path = os.path.join(dirname, 'plugins', 'platforms')
    os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = plugin_path
    
    app = QApplication(sys.argv)    # PySide6の実行
    window = MainWindow()           # ユーザがコーディングしたクラス
    window.show()                   # PySide6のウィンドウを表示
    sys.exit(app.exec())            # PySide6の終了

よしっ、実行してみましょうか。

radio_004.gif

素材

「右クリック」→「名前を付けて画像を保存」で入手できます。
「▶」をクリックして「▼」にすると画像が表示されます。

【こ↑こ↓をクリックして表示する】ラジオボタンのサンプルプログラムで使った素材
  • radio_000.png
    radio_000.png

  • radio_001.png
    radio_001.png

  • radio_002.png
    radio_002.png

  • radio_003.png
    radio_003.png

ラジオボタンで使用したシグナル

ラジオボタンで使用したシグナルについて説明を。

使用したシグナルはQButtonGroupのシグナルを使用しています。
ですのでQButtonGroupのシグナルについて一覧表を記載しますね。

シグナル 機能
buttonClicked グループに登録されているいずれかのボタンをクリックしたら実行
buttonPressed グループに登録されているいずれかのボタンを押したら実行
buttonReleased グループに登録されているいずれかのボタンを離したら実行
buttonToggled グループに登録されているボタンの選択状態が変更されたら実行
idClicked ???
idPressed ???
idReleased ???
idToggled ???

ラジオボタンそのものにシグナルは1つもないのでご注意を。
ラジオボタンにシグナルを与えたい場合は、以下の2つの方法があります。

① QRadioButtonの親クラスである「QAbstractButton」のシグナルを使う
② ラジオボタンのグループ化で使った「QButtonGroup」のシグナルを使う

今回は②でやってみました。

【公式リファレンス】ラジオボタン

QRadioButton
QButtonGroup

チェックボックス

与えられた選択子の中から何個でも選ぶことができるチェックボックスを使ってみます。
プログラムはこちらです。

# -*- encoding: shift-jis -*-
import PySide6
from PySide6.QtCore import (Qt)     # Qtの状態変数の取得に必要(チェックボックスの入力状態の取得に使う)
from PySide6.QtWidgets import (QApplication,
                               QCheckBox,       # チェックボックスを使うのに必要
                               QLabel,          # ラベルを使うのに必要
                               QPushButton,     # ボタンを使うのに必要
                               QWidget)
import os
import sys


# PySide6のアプリ本体(ユーザがコーディングしていく部分)
class MainWindow(QWidget):
    def __init__(self, parent=None):
        # 親クラスの初期化
        super().__init__(parent)
        
        # ウィンドウタイトル
        self.setWindowTitle("PySide6で作ったアプリです。")
        
        # ウィンドウ背景色を黒にする
        self.setStyleSheet("background-color: black")
        
        # チェックボックスを表示するメソッド
        self.SetCheckbox()
        
    # チェックボックスは別のメソッドに分けました
    def SetCheckbox(self):
        # 今回はリスト(配列)を使ってみましょう
        self.chBox = []
        
        # 1つ目のチェックボックス
        self.chBox.append(QCheckBox(self))  # チェックボックスを追加
        self.chBox[0].move(10, 10)          # チェックボックスの表示位置を絶対座標で指定
        self.chBox[0].setText("赤")         # チェックボックスに表示する文字
        self.chBox[0].setStyleSheet("background-color: white")  # チェックボックスの背景色を白にする
        # 1つ目のチェックボックスの入力状態が変化したら呼び出す処理
        self.chBox[0].stateChanged.connect(self.CallbackCheckboxStatechanged)
        
        # 2つ目のチェックボックス
        self.chBox.append(QCheckBox(self))  # チェックボックスを追加
        self.chBox[1].move(10, 35)          # チェックボックスの表示位置を絶対座標で指定
        self.chBox[1].setText("緑")         # チェックボックスに表示する文字
        self.chBox[1].setStyleSheet("background-color: white")  # チェックボックスの背景色を白にする
        # 2つ目のチェックボックスの入力状態が変化したら呼び出す処理
        self.chBox[1].stateChanged.connect(self.CallbackCheckboxStatechanged)
        
        # 3つ目のチェックボックス
        self.chBox.append(QCheckBox(self))  # 3つ目のチェックボックスを追加
        self.chBox[2].move(10, 60)          # チェックボックスの表示位置を絶対座標で指定
        self.chBox[2].setText("青")         # チェックボックスに表示する文字
        self.chBox[2].setStyleSheet("background-color: white")  # チェックボックスの背景色を白にする
        # 3つ目のチェックボックスの入力状態が変化したら呼び出す処理
        self.chBox[2].stateChanged.connect(self.CallbackCheckboxStatechanged)
        
    # チェックボックスの入力状態が変化したら実行する処理
    def CallbackCheckboxStatechanged(self):
        # 三原色(16進数)
        red   = 0x00
        green = 0x00
        blue  = 0x00
        
        if self.chBox[0].checkState() == Qt.Checked:
            red |= 0xAA     # ちょっと暗めの赤
        else:
            red |= 0x00     # 赤要素を無くす
        
        if self.chBox[1].checkState() == Qt.Checked:
            green |= 0xAA   # ちょっと暗めの緑
        else:
            green |= 0x00   # 緑要素を無くす
        
        if self.chBox[2].checkState() == Qt.Checked:
            blue |= 0xAA    # ちょっと暗めの青
        else:
            blue |= 0x00    # 青要素を無くす
        
        # RGBカラーコードに変換
        color = "#{0:02x}{1:02x}{2:02x}".format(red, green, blue)
        
        # 背景色を変更
        self.setStyleSheet("background-color: " + color + ";")


if __name__ == "__main__":
    # 環境変数にPySide6を登録
    dirname = os.path.dirname(PySide6.__file__)
    plugin_path = os.path.join(dirname, 'plugins', 'platforms')
    os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = plugin_path
    
    app = QApplication(sys.argv)    # PySide6の実行
    window = MainWindow()           # ユーザがコーディングしたクラス
    window.show()                   # PySide6のウィンドウを表示
    sys.exit(app.exec())            # PySide6の終了

実行しますね。

checkbox_000.gif

チェックボックスのシグナル

チェックボックスで使用したシグナルについて説明を。

QCheckBoxに存在するシグナルはたった一つだけです。

シグナル 機能
stateChanged チェックボックスの入力状態が変化したら処理を実行

QCheckBoxにはQAbstractButtonを親クラスとして持っており、親クラスのシグナルを利用することもできます。

【公式リファレンス】チェックボックス

QCheckBox

入力欄

一行だけ入力できるウィジェットがあります。
「そんなの使い道あるの?」と思うでしょうが、ログイン画面のようにメールアドレスやID、パスワードといった比較的少ない文字数を入力して終わるような場合に使います。

じゃあプログラムを見てましょう。

# -*- encoding: shift-jis -*-
import PySide6
from PySide6.QtWidgets import (QApplication,
                               QLabel,          # ラベルを使うのに必要
                               QLineEdit,       # 入力欄を使うのに必要
                               QWidget)
import os
import sys


# PySide6のアプリ本体(ユーザがコーディングしていく部分)
class MainWindow(QWidget):
    def __init__(self, parent=None):
        # 親クラスの初期化
        super().__init__(parent)
        
        # ウィンドウタイトル
        self.setWindowTitle("PySide6で作ったアプリです。")
        
        # ラベルを表示するメソッド
        self.SetLabel()
        
        # 入力欄を表示するメソッド
        self.SetLineedit()
        
    # ラベルは別のメソッドに分けました
    def SetLabel(self):
        label = QLabel(self)
        label.setText("なんか入力してね★")
        
    # 入力欄は別のメソッドに分けました
    def SetLineedit(self):
        self.lineEdit = QLineEdit(self) # 入力欄を使うことを宣言
        self.lineEdit.move(0, 25)       # 入力欄の表示位置を絶対座標で指定
        self.lineEdit.resize(200, 25)   # 入力欄のサイズを変更
        
        # 入力欄でEnterキーが押されたら実行する処理を呼び出す
        self.lineEdit.returnPressed.connect(self.CallbaclReturnpressedLineedit)
        
    # 入力欄でEnterキーが押されたら実行する処理
    def CallbaclReturnpressedLineedit(self):
        # 入力された内容を表示(text()メソッドで入力内容を取り出している)
        print(self.lineEdit.text())


if __name__ == "__main__":
    # 環境変数にPySide6を登録
    dirname = os.path.dirname(PySide6.__file__)
    plugin_path = os.path.join(dirname, 'plugins', 'platforms')
    os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = plugin_path
    
    app = QApplication(sys.argv)    # PySide6の実行
    window = MainWindow()           # ユーザがコーディングしたクラス
    window.show()                   # PySide6のウィンドウを表示
    sys.exit(app.exec())            # PySide6の終了

実行したった。

lineedit_000.gif

入力欄のシグナル

入力欄で使用したシグナルについて説明を。

入力欄には結構シグナルがあります。
まぁ、覚えなくても問題ないので「ふーん」って鼻ほじっていれば良いかと・・・

シグナル 機能
cursorPositionChanged 入力欄のカーソル位置が移動したら実行
editingFinished returnPressedとほぼ同じ
違いは「アクティブウィジェットが入力欄から別のウィジェットに変わった時も実行する」ところ
例えばアクティブウィジェットが入力欄→チェックボックスに変わった時にもeditingFinishedシグナルが発生します
inputRejected ???
returnPressed 入力欄でEnterキーが押されたら実行
selectionChanged 入力欄に入力された文字列を(Shift+カーソルやマウスで)選択したら実行
textChanged 入力欄の入力内容が1文字でも変化したら実行
textEditedとの違いは「入力し終わった後の入力内容が変化したことを検知する」シグナルであること
簡単に言えば「入力が終わったことを検知する」シグナル
textEdited 入力欄に1文字でも入力されたら実行
textChangedとの違いは「入力されたことを検知する」シグナルであること
簡単に言えば「入力が始まったことを検知する」シグナル

【公式リファレンス】入力欄

QLineEdit

テキストボックス

入力欄とは異なり何行でも入力できるのがテキストボックスです。
テキストエディタやメール本文などで使われてますね。

テキストボックスを求める、そんなあなたに捧げるプログラムがこちらになります。

# -*- encoding: shift-jis -*-
import PySide6
from PySide6.QtWidgets import (QApplication,
                               QPushButton,     # ボタンを使うのに必要
                               QTextEdit,       # テキストボックスを使うのに必要
                               QWidget)
import os
import sys


# PySide6のアプリ本体(ユーザがコーディングしていく部分)
class MainWindow(QWidget):
    def __init__(self, parent=None):
        # 親クラスの初期化
        super().__init__(parent)
        
        # ウィンドウタイトル
        self.setWindowTitle("PySide6で作ったアプリです。")
        
        # ボタンを表示するメソッド
        self.SetButton()
        
        # テキストボックスを表示するメソッド
        self.SetTextedit()
        
    # ボタンは別のメソッドに分けました
    def SetButton(self):
        # ボタンを使うことを宣言
        button = QPushButton(self)
        
        # ボタンに文字を表示する
        button.setText("なんか入力してからクリックするゾ")
        
        # ボタンがクリックされたら実行する処理を呼び出す
        button.clicked.connect(self.CallbackClickedPushbutton)
        
    # テキストボックスは別のメソッドに分けました
    def SetTextedit(self):
        self.textEdit = QTextEdit(self) # テキストボックスを使うことを宣言
        self.textEdit.move(0, 25)       # テキストボックスの表示位置を絶対座標で指定
        
        # ウィンドウのサイズを取得
        windowWidht = self.size().width()   # ウィンドウの横幅
        windowHeight = self.size().height() # ウィンドウの高さ
        
        # テキストボックスのサイズをウィンドウサイズに合わせる
        self.textEdit.resize(windowWidht, windowHeight)
        
    # ボタンがクリックされたら実行する処理
    def CallbackClickedPushbutton(self):
        # テキストボックスに書かれている内容を表示するだけ
        print(self.textEdit.toPlainText())


if __name__ == "__main__":
    # 環境変数にPySide6を登録
    dirname = os.path.dirname(PySide6.__file__)
    plugin_path = os.path.join(dirname, 'plugins', 'platforms')
    os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = plugin_path
    
    app = QApplication(sys.argv)    # PySide6の実行
    window = MainWindow()           # ユーザがコーディングしたクラス
    window.show()                   # PySide6のウィンドウを表示
    sys.exit(app.exec())            # PySide6の終了

実行しようず。

textbox_000.gif

テキストボックスのシグナル

今回テキストボックスのシグナルは使用しませんでしたが、テキストボックスには以下のシグナルがあります。

シグナル 機能
copyAvailable コピーができる状態になったら実行(文字を選択した状態でシグナルを発信)
currentCharFormatChanged ???(多分、文字フォントが変化したときに発信するシグナルっぽい)
cursorPositionChanged カーソル位置が変化したら実行
redoAvailable Ctrl+Yで直前の操作を取り消せれる状態になったら実行
要するに、Ctrl+Yが実行できる状態になったらこのシグナルが発信されるよってこと
selectionChanged 文字列を(Shift+カーソルまたはマウスで)選択した状態に実行
textChanged テキストボックスの入力内容が変化したら実行
undoAvailable Ctrl+Zで一つ前の操作に戻れる状態になったら実行
要するに、Ctrl+Zが実行できる状態になったらこのシグナルが発信されるよってこと

【公式リファレンス】テキストボックス

QTextEdit

ダイアログ

ダイアログはメインウィンドウとは別のウィンドウのことです。
「メインウィンドウには表示させたくないけど・・・でもなぁ~どこに表示させようかな~?」ってお悩みがあった時に願いを叶えてくれる、まさに痒い所に手が届く孫の手のような存在がダイアログです。

代表的な例が、テキストエディタの文字の大きさやフォントを変える際に出てくるアレ。
アレがまさにダイアログの一種です。

daialog_000.png

プログラムはこちら。

# -*- encoding: shift-jis -*-
import PySide6
from PySide6.QtWidgets import (QApplication,
                               QDialog,         # ダイアログを使うのに必要
                               QLabel,          # ラベルを使うのに必要
                               QPushButton,     # ボタンを使うのに必要
                               QWidget)
import os
import sys


# PySide6のアプリ本体(ユーザがコーディングしていく部分)
class MainWindow(QWidget):
    def __init__(self, parent=None):
        # 親クラスの初期化
        super().__init__(parent)
        
        # ウィンドウタイトル
        self.setWindowTitle("PySide6で作ったアプリです。")
        
        # ボタンを表示するメソッド
        self.SetButton()
        
    # ボタンは別のメソッドに分けました
    def SetButton(self):
        button = QPushButton(self)          # ボタンを使うことを宣言
        button.setText("最近だらしねぇな")  # ボタンに表示する文字
        # ボタンがクリックされたら呼び出す処理
        button.clicked.connect(self.CallbackClickedButton)
        
    # ボタンがクリックされたら実行する処理
    def CallbackClickedButton(self):
        dialog = QDialog()                              # ダイアログを使うことを宣言
        dialog.setWindowTitle("救いはないんですか!?") # ダイアログのタイトル
        
        label = QLabel(dialog)                  # 「ダイアログで」ラベルを使うことを宣言
        label.setText("ホイホイチャーハン")     # ラベルに文字を設定
        label.setStyleSheet("font-size: 32px;") # ラベル文字の大きさ
        
        # ダイアログをラベルの大きさに合わせる
        labelWidth = label.sizeHint().width()   # ラベルの横幅
        labelHeight = label.sizeHint().height() # ラベルの高さ
        dialog.resize(labelWidth, labelHeight)  # ダイアログのサイズ変更
        
        # ダイアログを表示
        dialog.exec()


if __name__ == "__main__":
    # 環境変数にPySide6を登録
    dirname = os.path.dirname(PySide6.__file__)
    plugin_path = os.path.join(dirname, 'plugins', 'platforms')
    os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = plugin_path
    
    app = QApplication(sys.argv)    # PySide6の実行
    window = MainWindow()           # ユーザがコーディングしたクラス
    window.show()                   # PySide6のウィンドウを表示
    sys.exit(app.exec())            # PySide6の終了

Execute。

dialog_001.gif

ちょっと意識してほしいこと

①ダイアログのインスタンス生成時の引数

よぉ~くプログラムを見ている人は気になったかもしれません。
例として、ボタンとダイアログのインスタンス生成を比較してみましょう。

# ボタンを使うことを宣言
button = QPushButton(self)

# ダイアログを使うことを宣言
dialog = QDialog()  # あれ? 引数のselfは?

このプログラムを見て、こう思った人はいたのではないでしょうか?


「ダイアログのインスタンス生成時にselfは指定しないの?」

はい、指定しなくても問題ありません。

指定しても全く問題ありませんが、ダイアログがウィンドウと重なり、使いにくくなってしまいます。

というのもダイアログは他のウィジェットとは決定的に異なる点があります。
その異なる点があるため、インスタンス生成時にselfを指定する必要がないのです。

では異なる点とは何か、それは次に続きます。

②ダイアログが他のウィジェットとは決定的に異なる点

ボタンやチェックボックス、テキストボックスなどのウィジェットとダイアログが決定的に異なる点。
それは


何らかのイベントが発生したときに表示される別のウィンドウ

ということです。

「ボタンをクリックした」とか「入力欄でEnterキーを押した」などのイベントがあることが前提で、別のウィンドウとしてダイアログが表示されます。

大事なのでもう一度言います。
別のウィンドウで開かれるのです。

メインウィンドウから独立した別ウィンドウとして表示されるので、ダイアログのインスタンス生成時にselfを指定する必要がないのです。

ダイアログのシグナル

今回ダイアログのシグナルは使用しませんでしたが、ダイアログには以下のシグナルがあります。

シグナル 機能
accepted ???
finished ダイアログを閉じたら実行
rejected ダイアログの操作が出来なくなったときに実行
ダイアログを閉じたときにも実行される

【公式リファレンス】ダイアログ

QDialog

メッセージボックス

メッセージボックスをものすごくザックリいうと「情報(文字)」と「ボタン」を表示するダイアログみたいなものです。

messagebox_000.png

メッセージボックスはユーザに「限られた選択肢の中からどうしますか?」という時が使いどころですね。
そんなメッセージボックスのプログラムがこちら。

# -*- encoding: shift-jis -*-
import PySide6
from PySide6.QtWidgets import (QApplication,
                               QLabel,          # ラベルを使うのに必要
                               QMessageBox,     # メッセージボックスを使うのに必要
                               QPushButton,     # ボタンを使うのに必要
                               QWidget)
import os
import sys


# PySide6のアプリ本体(ユーザがコーディングしていく部分)
class MainWindow(QWidget):
    def __init__(self, parent=None):
        # 親クラスの初期化
        super().__init__(parent)
        
        # ウィンドウタイトル
        self.setWindowTitle("PySide6で作ったアプリです。")
        
        # ボタンを表示するメソッド
        self.SetButton()
        
    # ボタンは別のメソッドに分けました
    def SetButton(self):
        label = QLabel(self)
        label.setText("どれかをクリックするゾ")
        
        # 「情報」を表示するボタン
        buttonInfo = QPushButton(self)              # ボタンを使うことを宣言
        buttonInfo.move(10, 30)                     # ボタンの表示位置を絶対座標で指定
        buttonInfo.setText("情報")                  # ボタンに表示する文字
        buttonInfo.setStyleSheet("color: #00AAAA")  # ボタン上の文字色
        # 「情報」ボタンをクリックしたら呼び出す処理
        buttonInfo.clicked.connect(self.CallbackClickedPushbuttonInformation)
        
        # 「注意」を表示するボタン
        buttonWarn = QPushButton(self)              # ボタンを使うことを宣言
        buttonWarn.move(10, 60)                     # ボタンの表示位置を絶対座標で指定
        buttonWarn.setStyleSheet("color: #AAAA00")  # ボタンに表示する文字
        buttonWarn.setText("注意")                  # ボタン上の文字色
        # 「注意」ボタンをクリックしたら呼び出す処理
        buttonWarn.clicked.connect(self.CallbackClickedPushbuttonWarning)
        
        # 「警告」を表示するボタン
        buttonCrit = QPushButton(self)              # ボタンを使うことを宣言
        buttonCrit.move(10, 90)                     # ボタンの表示位置を絶対座標で指定
        buttonCrit.setStyleSheet("color: #AA00AA")  # ボタンに表示する文字
        buttonCrit.setText("警告")                  # ボタン上の文字色
        # 「警告」ボタンをクリックしたら呼び出す処理
        buttonCrit.clicked.connect(self.CallbackClickedPushbuttonCritical)
        
    # 「情報」ボタンをクリックしたら実行する処理
    def CallbackClickedPushbuttonInformation(self):
        info = QMessageBox()                    # メッセージボックスを使うことを宣言
        info.setWindowTitle("こ↑こ↓")         # メッセージボックスのタイトル
        info.setText("また君か壊れるなぁ")      # メッセージボックスの本文
        info.setIcon(QMessageBox.Information)   # メッセージボックスの種別は「情報」
        info.setStandardButtons(QMessageBox.Ok) # メッセージボックス上のボタン(「OK」ボタンのみ)
        # メッセージボックス上のボタンを押したら呼び出す処理
        info.buttonClicked.connect(self.CallbackButtonclickedMessagebox)
        info.exec() # メッセージボックスを表示
        
    # 「注意」ボタンをクリックしたら実行する処理
    def CallbackClickedPushbuttonWarning(self):
        warn = QMessageBox()                                            # メッセージボックスを使うことを宣言
        warn.setWindowTitle("あっそうだ(唐突)、オイKMR!")            # メッセージボックスの本文
        warn.setText("お前さっき俺が着替えてる時、チラチラ見てただろ")  # メッセージボックスの本文
        warn.setIcon(QMessageBox.Warning)                               # メッセージボックスの種別は「注意」
        # メッセージボックス上のボタン
        warn.setStandardButtons(QMessageBox.No |    # 「No」ボタンを表示
                                QMessageBox.Yes)    # 「Yes」ボタンを表示
        # メッセージボックス上のボタンを押したら呼び出す処理
        warn.buttonClicked.connect(self.CallbackButtonclickedMessagebox)
        warn.exec() # メッセージボックスを表示
        
    # 「警告」ボタンをクリックしたら実行する処理
    def CallbackClickedPushbuttonCritical(self):
        crit = QMessageBox()                        # メッセージボックスを使うことを宣言
        crit.setWindowTitle("青いツナギを着たイイ男が語りかけてくる")   # メッセージボックスのタイトル
        crit.setText("やらないか?")                # メッセージボックスの本文
        crit.setIcon(QMessageBox.Critical)          # メッセージボックスの種別は「警告」
        # メッセージボックス上のボタン
        crit.setStandardButtons(QMessageBox.Ok |    # 「OK」ボタンを表示
                                QMessageBox.Yes|    # 「Yes」ボタンを表示
                                QMessageBox.Apply)  # 「Apply(適用)」ボタンを表示
        # メッセージボックス上のボタンを押したら呼び出す処理
        crit.buttonClicked.connect(self.CallbackButtonclickedMessagebox)
        crit.exec() # メッセージボックスを表示
        
    # メッセージボックス上のボタンを押したら実行する処理
    def CallbackButtonclickedMessagebox(self, type):
        # メッセージボックス上の押されたボタンの種類(「OK」や「Yes」など)を表示
        print(type.text())


if __name__ == "__main__":
    # 環境変数にPySide6を登録
    dirname = os.path.dirname(PySide6.__file__)
    plugin_path = os.path.join(dirname, 'plugins', 'platforms')
    os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = plugin_path
    
    app = QApplication(sys.argv)    # PySide6の実行
    window = MainWindow()           # ユーザがコーディングしたクラス
    window.show()                   # PySide6のウィンドウを表示
    sys.exit(app.exec())            # PySide6の終了

さぁ実行するぜ!

messagebox_001.gif

ちょっと意識してほしいこと

ダイアログと同様にメッセージボックスも他のウィジェットとはことなり、あるイベントが起こってから表示されるものです。

正直ダイアログの項目と全く同じなので、省略します。
単に、メッセージボックスで意識することはダイアログと同じだよってこと。

ダイアログのちょっと意識してほしいこと

メッセージボックスのシグナル

メッセージボックスで使用したシグナルについて説明を。

メッセージボックスのシグナルはたった一つだけです。
そんなに複雑なものでもないのでサクッと押さえちゃいましょう。

シグナル 機能
buttonClicked メッセージボックス上のボタンをクリックしたら実行

ちなみにメッセージボックスにはQDialogを親クラスとして持っているので、ダイアログのシグナルを使用することもできます。

【公式リファレンス】メッセージボックス

QMessageBox

コンボボックス

コンボボックスはラジオボタンに似ていて、複数ある選択肢の中から一つを選択するウィジェットです。
ラジオボタンと異なる点は次の通り。

  • 一つのウィジェットに複数の選択肢を割り振ることができる
  • 入力欄のように入力して検索をすることができる

といったところですかね。

そんなコンボボックスのプログラムがこちらです。

# -*- encoding: shift-jis -*-
import PySide6
from PySide6.QtWidgets import (QApplication,
                               QComboBox,       # コンボボックスを使うのに必要
                               QWidget)
import os
import sys


# PySide6のアプリ本体(ユーザがコーディングしていく部分)
class MainWindow(QWidget):
    def __init__(self, parent=None):
        # 親クラスの初期化
        super().__init__(parent)
        
        # ウィンドウタイトル
        self.setWindowTitle("PySide6で作ったアプリです。")
        
        # ウィンドウの起動位置とサイズ
        self.setGeometry(300, 200, 200, 50)
        
        # コンボボックスを表示するメソッド
        self.SetCombobox()
        
    # コンボボックスは別のメソッドに分けました
    def SetCombobox(self):
        # コンボボックスを使うことを宣言
        self.combobox = QComboBox(self)
        
        # コンボボックスの入力を無効
        self.combobox.setEditable(False)
        
        # 追加順にIDが0から割り振られる
        self.combobox.addItem("もしもし。ポリスメン?")         # ID: 0
        self.combobox.addItem("いっぱいちゅき")                 # ID: 1
        self.combobox.addItem("オッテメーいい度胸してんねー")   # ID: 2
        self.combobox.addItem("ああ、血の色をごまかせるな")     # ID: 3
        self.combobox.addItem("さてはアンチだなオメー")         # ID: 4
        
        # コンボボックスの選択中のIDが変更されたら呼び出す処理
        self.combobox.currentIndexChanged.connect(self.CallbackCurrentindexchangedCombobox)
        
    # コンボボックスの選択中のIDが変更されたら実行する処理
    def CallbackCurrentindexchangedCombobox(self):
        print(self.combobox.currentIndex()) # 選択中のIDを表示
        print(self.combobox.currentText())  # 選択中の文字列を表示


if __name__ == "__main__":
    # 環境変数にPySide6を登録
    dirname = os.path.dirname(PySide6.__file__)
    plugin_path = os.path.join(dirname, 'plugins', 'platforms')
    os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = plugin_path
    
    app = QApplication(sys.argv)    # PySide6の実行
    window = MainWindow()           # ユーザがコーディングしたクラス
    window.show()                   # PySide6のウィンドウを表示
    sys.exit(app.exec())            # PySide6の終了

combobox_000.gif

コンボボックスのシグナル

コンボボックスで使用したシグナルについて説明を。

コンボボックスのシグナルはいまいちわからないものが多かったので、よく使うものだけ解説します。
あとはリファレンスを見て、どうぞ。

シグナル 機能
activated ???
currentIndexChanged 選択中のIDが変更されたら実行
currentTextChanged 選択中の文字列が変更された実行
editTextChanged コンボボックス内の選択肢に何かしら入力されたら実行
highlighted ???
textActivated ???
textHighlighted ???

【公式リファレンス】コンボボックス

QComboBox

スピンボックス

スピンボックスはコンボボックスやはラジオボタンと同じく、複数ある選択肢の中から一つを選択するウィジェットです。
他との違いは、▲▼ボタンをポチポチして一つずつ選択肢を連続的に変化させる点にあります。

そんなスピンボックスのコードがこ↑こ↓。

# -*- encoding: shift-jis -*-
import PySide6
from PySide6.QtWidgets import (QApplication,
                               QSpinBox,        # スピンボックスを使うのに必要
                               QWidget)
import os
import sys


# PySide6のアプリ本体(ユーザがコーディングしていく部分)
class MainWindow(QWidget):
    def __init__(self, parent=None):
        # 親クラスの初期化
        super().__init__(parent)
        
        # ウィンドウタイトル
        self.setWindowTitle("PySide6で作ったアプリです。")
        
        # ウィンドウの起動位置とサイズ
        self.setGeometry(300, 300, 400, 150)
        
        # スライダーを表示するメソッド
        self.SetSpinbox()
        
    # スライダーは別のメソッドに分けました
    def SetSpinbox(self):
        self.spinbox = QSpinBox(self)   # スピンボックスを使うことを宣言
        self.spinbox.resize(100, 25)    # スピンボックスのサイズを変更
        self.spinbox.setSingleStep(1)   # スピンボックスを1ずつ加減する
        self.spinbox.setRange(-1, 36)   # 設定範囲を-1から36まで
        
        # スピンボックスの値が更新されたら呼び出す処理
        self.spinbox.valueChanged.connect(self.CallbackValuechangedSpinbox)
        
    # スピンボックスの値が更新されたら実行する処理
    def CallbackValuechangedSpinbox(self):
        # スピンボックスの現在の値を表示
        print(self.spinbox.value())
        
        if self.spinbox.value() == 14:
            print("14万!?")
        elif self.spinbox.value() == 24:
            print("24歳、学生です")
        elif self.spinbox.value() == 36:
            print("36…普通だな!")


if __name__ == "__main__":
    # 環境変数にPySide6を登録
    dirname = os.path.dirname(PySide6.__file__)
    plugin_path = os.path.join(dirname, 'plugins', 'platforms')
    os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = plugin_path
    
    app = QApplication(sys.argv)    # PySide6の実行
    window = MainWindow()           # ユーザがコーディングしたクラス
    window.show()                   # PySide6のウィンドウを表示
    sys.exit(app.exec())            # PySide6の終了

動かした。

spinbox_000.gif

スピンボックスのシグナル

スピンボックスのシグナルはたった2つだけです。
おまけにその内容も簡単なので、サクッと抑えちゃってください。

シグナル 機能
textChanged 選択中の文字が更新されたら実行
valueChanged 選択中の値が更新されたら実行

QAbstractSpinBox

【公式リファレンス】スピンボックス

QSpinBox

スライダー

スライダーはマウスで値を連続的に変化できるウィジェットです。
ちょっとした数値の変化を見たい時に使うとハッピーになれます。

スライダーのプログラムはこちら。

# -*- encoding: shift-jis -*-
import PySide6
from PySide6.QtCore import (Qt) # スライダーの向きを設定するのに必要
from PySide6.QtWidgets import (QApplication,
                               QLabel,          # ラベルを使うのに必要
                               QSlider,         # スライダーを使うのに必要
                               QWidget)
import os
import sys


# PySide6のアプリ本体(ユーザがコーディングしていく部分)
class MainWindow(QWidget):
    def __init__(self, parent=None):
        # 親クラスの初期化
        super().__init__(parent)
        
        # ウィンドウタイトル
        self.setWindowTitle("PySide6で作ったアプリです。")
        
        # ウィンドウの起動位置とサイズ
        self.setGeometry(500, 300, 400, 150)
        
        # スライダーを表示するメソッド
        self.SetSlider()
        
    # スライダーは別のメソッドに分けました
    def SetSlider(self):
        # スライダーを使うことを宣言
        self.slider = QSlider(self)
        
        self.slider.resize(300, 30)     # スライダーのサイズ
        self.slider.setTickInterval(1)  # スライダーの加減値を1
        self.slider.setMinimum(8)       # スライダーの最小値
        self.slider.setMaximum(64)      # スライダーの最大値
        self.slider.setOrientation(Qt.Horizontal)   # スライダーを横向きにする
        self.slider.setTickPosition(QSlider.TicksBelow)
        # スライダーの値が更新されたら呼び出す処理
        self.slider.valueChanged.connect(self.CallbackValuechangedSlider)
        
        # スライダーの設定値を表示するラベル
        self.label = QLabel(self)
        self.label.move(310, 5)
        self.label.resize(20, 10)
        self.label.setText(str(self.slider.value()))
        
        # スライダーの設定値を反映させるラベル
        self.commentLabel = QLabel(self)
        self.commentLabel.move(10, 50)
        self.commentLabel.resize(500, 100)
        self.commentLabel.setText("オンドゥルルラギッタンディスカー!!")
        
    # スライダーの値が更新されたら実行する処理
    def CallbackValuechangedSlider(self):
        # スライダーの設定値を再表示
        self.label.setText(str(self.slider.value()))
        
        # スライダーの設定値からフォントサイズを変更
        self.commentLabel.setStyleSheet("font-size: {0}px;".format(self.slider.value()))


if __name__ == "__main__":
    # 環境変数にPySide6を登録
    dirname = os.path.dirname(PySide6.__file__)
    plugin_path = os.path.join(dirname, 'plugins', 'platforms')
    os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = plugin_path
    
    app = QApplication(sys.argv)    # PySide6の実行
    window = MainWindow()           # ユーザがコーディングしたクラス
    window.show()                   # PySide6のウィンドウを表示
    sys.exit(app.exec())            # PySide6の終了

まぁこんな感じに動きます。

slider_000.gif

スライダーで使用したシグナル

スライダーで使用したシグナルについて説明を。

使用したシグナルはQAbstractSliderのシグナルを使用しています。
ですのでQAbstractSliderのシグナルについて一覧表を記載しますね。

シグナル 機能
actionTriggered ???
rangeChanged スライダーやダイヤル、スクロールバーの可動範囲や、取得できる値の範囲が変更されたら実行
sliderMoved スライダーやダイヤル、スクロールバーを動かしたら処理を実行
sliderPressed スライダーやダイヤル、スクロールバーを押したら処理を実行
sliderReleased スライダーやダイヤル、スクロールバーを離したら処理を実行
valueChanged スライダーやダイヤル、スクロールバーの値が更新されたら処理を実行

スライダーそのものにシグナルは1つもないのでご注意を。
スライダーにシグナルを与えたい場合は、親クラスのQAbstractSliderのシグナルを利用します。

【公式リファレンス】スライダー

QSlider

ダイヤル

スライダーより省スペースで同じようなことできる、なかなか良いヤツです。

そんなダイヤルを使ったプログラムがこちらになります。

# -*- encoding: shift-jis -*-
import PySide6
from PySide6.QtWidgets import (QApplication,
                               QDial,           # ダイヤルを使うのに必要
                               QLabel,          # ラベルを使うのに必要
                               QWidget)
import os
import sys


# PySide6のアプリ本体(ユーザがコーディングしていく部分)
class MainWindow(QWidget):
    def __init__(self, parent=None):
        # 親クラスの初期化
        super().__init__(parent)
        
        # ウィンドウタイトル
        self.setWindowTitle("PySide6で作ったアプリです。")
        
        # ウィンドウサイズの変更
        self.resize(300, 150)
        
        # ダイヤルを表示するメソッド
        self.SetDial()
        
        # ラベルを表示するメソッド
        self.SetLabel()
        
    # ダイヤルは別のメソッドに分けました
    def SetDial(self):
        # 1つ目のダイヤル
        self.redDial = QDial(self)      # ダイヤルを使うことを宣言
        self.redDial.move(0, 0)         # ダイヤルの表示位置を絶対座標で指定
        self.redDial.setMinimum(0)      # ダイヤルの最小値を「0」に設定
        self.redDial.setMaximum(255)    # ダイヤルの最小値を「255」に設定
        self.redDial.setSingleStep(1)   # ダイアルを回した時に加減される値を「1」にする
        # ダイアルの値が変化したら呼び出す処理
        self.redDial.valueChanged.connect(self.CallbackValuechangedDial)
        
        # 2つ目のダイヤル
        self.greenDial = QDial(self)    # ダイヤルを使うことを宣言
        self.greenDial.move(100, 0)     # ダイヤルの表示位置を絶対座標で指定
        self.greenDial.setMinimum(0)    # ダイヤルの最小値を「0」に設定
        self.greenDial.setMaximum(255)  # ダイヤルの最小値を「255」に設定
        self.greenDial.setSingleStep(1) # ダイアルを回した時に加減される値を「1」にする
        # ダイアルの値が変化したら呼び出す処理
        self.greenDial.valueChanged.connect(self.CallbackValuechangedDial)
        
        # 3つ目のダイヤル
        self.blueDial = QDial(self)     # ダイヤルを使うことを宣言
        self.blueDial.move(200, 0)      # ダイヤルの表示位置を絶対座標で指定
        self.blueDial.setMinimum(0)     # ダイヤルの最小値を「0」に設定
        self.blueDial.setMaximum(255)   # ダイヤルの最小値を「255」に設定
        self.blueDial.setSingleStep(1)  # ダイアルを回した時に加減される値を「1」にする
        # ダイアルの値が変化したら呼び出す処理
        self.blueDial.valueChanged.connect(self.CallbackValuechangedDial)
        
    # ラベルは別のメソッドに分けました
    def SetLabel(self):
        self.label = QLabel(self)
        self.label.setText("よく来たわね、いらっしゃい")
        self.label.move(70, 110)
        self.label.setStyleSheet("font-size: 16px;")
        
    def CallbackValuechangedDial(self):
        # 三原色
        red   = self.redDial.value()    # 1つ目のダイヤルの値を取得
        green = self.greenDial.value()  # 2つ目のダイヤルの値を取得
        blue  = self.blueDial.value()   # 3つ目のダイヤルの値を取得
        
        # RGBカラーコードに変換(ラベルの背景の色)
        backgroundColor = "#{0:02x}{1:02x}{2:02x}".format(red, green, blue)
        
        # RGBカラーコードの反転色(ラベルの文字の色)
        fontColor = "#{0:02x}{1:02x}{2:02x}".format(255-red, 255-green, 255-blue)
        
        # ラベルの見た目の設定にダイヤルの値を反映({}の中で{}を使う場合、一番外側は{{}}にすること)
        labelStyle = """ QLabel {{
            font-size: 16px;
            color: {0};
            background-color: {1};
        }}""".format(fontColor, backgroundColor)
        
        # ラベルの見た目を変更
        self.label.setStyleSheet(labelStyle)

if __name__ == "__main__":
    # 環境変数にPySide6を登録
    dirname = os.path.dirname(PySide6.__file__)
    plugin_path = os.path.join(dirname, 'plugins', 'platforms')
    os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = plugin_path
    
    app = QApplication(sys.argv)    # PySide6の実行
    window = MainWindow()           # ユーザがコーディングしたクラス
    window.show()                   # PySide6のウィンドウを表示
    sys.exit(app.exec())            # PySide6の終了

さぁさぁ実行しようぜ。

dial_000.gif

ダイヤルで使用したシグナル

ダイヤルで使用したシグナルについて説明を。

使用したシグナルはQAbstractSliderのシグナルを使用しています。
ですのでQAbstractSliderのシグナルについて一覧表を記載しますね。

シグナル 機能
actionTriggered ???
rangeChanged スライダーやダイヤル、スクロールバーの可動範囲や、取得できる値の範囲が変更されたら実行
sliderMoved スライダーやダイヤル、スクロールバーを動かしたら処理を実行
sliderPressed スライダーやダイヤル、スクロールバーを押したら処理を実行
sliderReleased スライダーやダイヤル、スクロールバーを離したら処理を実行
valueChanged スライダーやダイヤル、スクロールバーの値が更新されたら処理を実行

ダイヤルそのものにシグナルは1つもないのでご注意を。
ダイヤルにシグナルを与えたい場合は、親クラスのQAbstractSliderのシグナルを利用します。

【公式リファレンス】dial

QDial

さらに学べる私の記事(宣伝)

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
9
Help us understand the problem. What are the problem?