Qt QCheckBoxでつまずかない!よくあるエラーと解決策を徹底解説

2025-06-01

QCheckBoxは、Qtフレームワークが提供するウィジェットの一つで、ユーザーが**オン/オフ(チェック/アンチェック)**の状態を選択できる、いわゆる「チェックボックス」を表現します。設定画面やオプション選択など、複数の項目の中から任意のものを選んだり、機能を有効/無効にしたりする場面でよく利用されます。

主な特徴と機能

  1. 状態の選択:

    • 通常は「チェック済み (Checked)」と「未チェック (Unchecked)」の2つの状態を持ちます。
    • オプションとして、setTristate(true) を呼び出すことで「部分的にチェック済み (PartiallyChecked)」という3つ目の状態を持つこともできます。これは、例えば親となるチェックボックスが、全ての子項目がチェックされているわけでも、全てチェックされていないわけでもない状態を表す場合に便利です。
  2. テキストラベル:

    • チェックボックスの横に表示されるテキストラベルを設定できます。コンストラクタで指定することも、setText() メソッドで後から設定することも可能です。
    • テキストには、ショートカットキーを指定するためにアンパサンド (&) を含めることができます(例: QCheckBox("C&ase sensitive") とすると、Alt+A でチェックボックスを操作できるようになります)。
  3. シグナルとスロット:

    • QCheckBoxは、状態が変化したときに特定のシグナルを発行します。最もよく使われるのは以下の2つです。
      • stateChanged(int state): チェックボックスの状態(Qt::Checked, Qt::Unchecked, Qt::PartiallyChecked のいずれか)が変化したときに発行されます。
      • clicked(bool checked): チェックボックスがクリックされたときに発行されます。checked 引数は、クリック後のチェック状態を示します。
    • これらのシグナルをカスタムのスロット(関数)に接続することで、チェックボックスの状態変化に応じて特定の処理を実行することができます。
  4. 状態の取得と設定:

    • 現在のチェック状態を取得するには、isChecked() (bool値を返す) や checkState() (Qt::CheckState 列挙値を返す) メソッドを使用します。
    • プログラムからチェック状態を設定するには、setChecked(bool)setCheckState(Qt::CheckState) メソッドを使用します。

使用例 (Python with PyQt/PySide)

import sys
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QCheckBox
from PyQt6.QtCore import Qt

class MainWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("QCheckBox の例")
        self.setGeometry(100, 100, 300, 200)

        layout = QVBoxLayout()

        # シンプルなチェックボックス
        self.checkbox1 = QCheckBox("オプション A")
        self.checkbox1.setChecked(True) # デフォルトでチェック済みにする
        self.checkbox1.stateChanged.connect(self.on_checkbox1_state_changed)
        layout.addWidget(self.checkbox1)

        # 3つの状態を持つチェックボックス
        self.checkbox2 = QCheckBox("オプション B (三状態)")
        self.checkbox2.setTristate(True) # 三状態を有効にする
        self.checkbox2.setCheckState(Qt.CheckState.PartiallyChecked) # 部分的にチェック済みにする
        self.checkbox2.stateChanged.connect(self.on_checkbox2_state_changed)
        layout.addWidget(self.checkbox2)

        self.setLayout(layout)

    def on_checkbox1_state_changed(self, state):
        if state == Qt.CheckState.Checked.value: # PyQt6の場合、列挙型の値を取得
            print("オプション A がチェックされました。")
        else:
            print("オプション A がアンチェックされました。")

    def on_checkbox2_state_changed(self, state):
        if state == Qt.CheckState.Checked.value:
            print("オプション B が完全にチェックされました。")
        elif state == Qt.CheckState.Unchecked.value:
            print("オプション B がアンチェックされました。")
        else:
            print("オプション B が部分的にチェックされました。")

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec())


QCheckBoxは比較的シンプルなウィジェットですが、それでもいくつかの一般的な問題に遭遇することがあります。

シグナルとスロットの接続ミス

問題: チェックボックスの状態が変わっても、対応するスロット(処理を行う関数/メソッド)が呼び出されない。

原因:

  • Qt Designerを使用している場合、オブジェクト名が変更されたのに、それに合わせてスロット名(例: on_checkBoxName_stateChanged(int))が更新されていない。
  • シグナルの引数とスロットの引数の型が一致していない。特に、stateChanged(int)clicked(bool)を混同しやすい。
  • QCheckBoxのシグナルと、それを受け取るスロットが正しく接続されていない。

トラブルシューティング:

  • デバッグ出力: スロットの先頭にprint()文(Python)やqDebug()(C++)を入れて、スロットがそもそも呼び出されているかを確認します。
  • 接続コードの確認:
    • Python (PyQt/PySide) の場合: self.checkBox.stateChanged.connect(self.my_slot_function)
    • C++ の場合: connect(checkBox, &QCheckBox::stateChanged, this, &MyClass::mySlotFunction); (新しい記法)
    • C++ の古い記法 (SIGNAL/SLOTマクロ) を使っている場合は、タイポがないか注意深く確認してください。
  • スロットの引数の確認:
    • stateChanged(int)に接続するスロットは、int型の引数を一つ取る必要があります。
    • clicked(bool)に接続するスロットは、bool型の引数を一つ取る必要があります。
  • シグナルの確認:
    • 状態変更に対応する場合は、stateChanged(int state)シグナルを使用するのが一般的です。このシグナルは、チェックボックスが「チェック済み」「未チェック」「部分的にチェック済み」のどの状態になったかを示すint型の引数(Qt::Checked, Qt::Unchecked, Qt::PartiallyChecked の値)を渡します。
    • クリックイベントにのみ反応させたい場合は、clicked(bool checked)シグナルを使用します。これは、クリック後のチェック状態(trueまたはfalse)を渡します。

setTristate() の誤用または理解不足

問題:

  • isChecked()を使っても、部分的にチェックされた状態を検出できない。
  • チェックボックスが3つの状態(チェック済み、未チェック、部分的にチェック済み)の間で期待通りに切り替わらない。

原因:

  • setTristate(true)を設定した場合、isChecked()は「部分的にチェック済み」の状態ではfalseを返します。この状態を正しく検出するにはcheckState()を使用する必要があります。
  • setTristate(true)を呼び出していないのに、部分的にチェックされた状態を設定しようとしている。

トラブルシューティング:

  • 状態の取得:
    • Qt::CheckedまたはQt::Uncheckedのみを考慮する場合はisChecked()を使用します。
    • Qt::PartiallyCheckedを含む全ての状態を正確に取得したい場合は、checkState()メソッドを使用し、返り値のQt::CheckState列挙型(Qt::Checked, Qt::Unchecked, Qt::PartiallyChecked)を評価します。
  • setTristate(true)の呼び出し: 3つの状態が必要な場合は、必ずチェックボックスの初期化時にsetTristate(true)を呼び出してください。
  • 3つの状態が必要か確認: 2つの状態(オン/オフ)で十分な場合は、setTristate(false)(デフォルト)のままで問題ありません。

プログラムによる状態変更時の再描画(C++の場合によく見られる)

問題: プログラム的にsetChecked()setCheckState()でチェックボックスの状態を変更しても、UIにすぐに反映されない(マウスオーバーなど、何らかのUIイベントが発生するまで古い表示のまま)。

原因: 特に古いQtのバージョンや特定の環境で、QCheckBoxのスタイルや描画が正しく更新されない場合があります。

トラブルシューティング:

  • これは一時的な回避策であり、通常はQtが自動的に再描画を処理すべきです。問題が頻繁に発生する場合は、Qtのバージョンアップを検討したり、スタイルシートの適用方法を確認したりすることも有効です。
  • update()またはrepaint()の呼び出し: 状態変更後に、対象のQCheckBoxインスタンスに対してupdate()またはrepaint()メソッドを呼び出すことで、強制的に再描画させることができます。
    • 例: ui->checkBox->setCheckState(Qt::Checked); ui->checkBox->update();

スタイルシート(CSS)の適用問題

問題: QCheckBoxにスタイルシートを適用しても、期待通りに見た目が変わらない、または一部のプロパティしか適用されない。

原因:

  • QCheckBoxの内部構造(サブコントロール)に関する知識不足。
  • Qtウィジェットのスタイルシートの継承や優先順位のルールを誤解している。
  • スタイルシートのセレクタが正しくない。

トラブルシューティング:

  • 競合するスタイルシート: 複数の場所(QSSファイル、インラインスタイル、親ウィジェットのスタイル)でスタイルシートが設定されている場合、競合が発生する可能性があります。より具体的なセレクタを持つスタイルが優先されます。
  • プロパティの確認: 全てのCSSプロパティがQtウィジェットに適用できるわけではありません。Qtのスタイルシートリファレンスで、特定のウィジェットに適用可能なプロパティを確認します。
  • セレクタの正確性: QCheckBoxだけでなく、その中のインジケータ(チェックマーク)やテキスト(ラベル)部分にも個別にスタイルを適用できる場合があります。
    • 例: QCheckBox::indicator { ... }, QCheckBox::text { ... }

QButtonGroup との連携

問題: 複数のチェックボックスをグループ化して、ラジオボタンのように排他的な選択(一つを選んだら他が解除される)を実現したいが、うまくいかない。

原因:

  • QButtonGroupQCheckBoxを追加し、setExclusive(true)を設定していない。
  • QButtonGroup視覚的なグループ化を提供するものではなく、論理的なグループ化を提供します。UI上で枠などで視覚的にグループ化したい場合は、QGroupBoxなどのコンテナウィジェットを使用する必要があります。

トラブルシューティング:

  • 排他的選択: QButtonGroupインスタンスを作成し、その中にQCheckBoxを追加した後、buttonGroup.setExclusive(true)を呼び出すことで、そのグループ内のチェックボックスがラジオボタンのように動作するようになります。
  • QButtonGroupの役割理解: QButtonGroupは、複数のボタン(QCheckBoxQRadioButtonなど)を論理的に管理し、排他的な選択などを制御するために使用します。UI上の見た目には影響しません。
# 排他的なQCheckBoxの例 (PyQt)
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QCheckBox, QButtonGroup, QGroupBox

class ExclusiveCheckBoxExample(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("排他的QCheckBoxの例")
        self.setGeometry(100, 100, 300, 200)

        main_layout = QVBoxLayout()
        self.setLayout(main_layout)

        # 視覚的なグループボックス
        group_box = QGroupBox("好きな色を選んでください(一つだけ)")
        group_layout = QVBoxLayout()
        group_box.setLayout(group_layout)
        main_layout.addWidget(group_box)

        # 論理的なボタン(チェックボックス)グループ
        self.color_button_group = QButtonGroup(self)
        self.color_button_group.setExclusive(True) # 排他的選択を有効にする

        colors = ["赤", "緑", "青"]
        for i, color in enumerate(colors):
            checkbox = QCheckBox(color)
            group_layout.addWidget(checkbox)
            self.color_button_group.addButton(checkbox, i) # ボタンとIDを追加

        self.color_button_group.buttonClicked.connect(self.on_color_selected)

    def on_color_selected(self, button):
        print(f"{button.text()} が選択されました。(排他的)")

if __name__ == "__main__":
    app = QApplication([])
    window = ExclusiveCheckBoxExample()
    window.show()
    app.exec()


基本的なチェックボックス (Python with PyQt/PySide)

最も基本的な使用例で、チェックボックスを作成し、その状態が変化したときにメッセージを表示します。

import sys
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QCheckBox
from PyQt6.QtCore import Qt # Qt.CheckState を使用するためにインポート

class BasicCheckBoxExample(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("基本的なチェックボックスの例")
        self.setGeometry(100, 100, 300, 150)

        layout = QVBoxLayout()
        self.setLayout(layout)

        # QCheckBox の作成
        # コンストラクタでテキストと親ウィジェットを指定
        self.checkBox = QCheckBox("機能を有効にする", self)

        # チェックボックスの初期状態を設定 (オプション)
        self.checkBox.setChecked(True) # デフォルトでチェック済みにする

        # stateChanged シグナルをスロットに接続
        # stateChanged は int (Qt.CheckState の値) を引数に取る
        self.checkBox.stateChanged.connect(self.on_checkbox_state_changed)

        layout.addWidget(self.checkBox)

    def on_checkbox_state_changed(self, state):
        """チェックボックスの状態が変更されたときに呼び出されるスロット"""
        if state == Qt.CheckState.Checked.value: # PyQt6の場合、列挙型の値を取得
            print("機能が有効になりました!")
        else:
            print("機能が無効になりました。")

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = BasicCheckBoxExample()
    window.show()
    sys.exit(app.exec())

解説:

  • on_checkbox_state_changed(self, state): スロットメソッドは、state 引数としてQt.CheckStateの値(Qt.CheckedQt.UncheckedQt.PartiallyChecked)を受け取ります。この値を使って、チェックボックスの現在の状態を判断します。
  • self.checkBox.stateChanged.connect(self.on_checkbox_state_changed): チェックボックスの状態が変更されると、stateChanged シグナルが発せられ、それが on_checkbox_state_changed メソッドに接続されます。
  • self.checkBox.setChecked(True): チェックボックスを初期状態でチェック済みにします。
  • QCheckBox("機能を有効にする", self): "機能を有効にする" というテキストを持つチェックボックスを作成します。self は親ウィジェットを示します。

三状態チェックボックス (C++)

「チェック済み」「未チェック」「部分的にチェック済み」の3つの状態を持つチェックボックスの例です。

#include <QApplication>
#include <QWidget>
#include <QVBoxLayout>
#include <QCheckBox>
#include <QDebug> // デバッグ出力用

class TristateCheckBoxExample : public QWidget
{
    Q_OBJECT // シグナル/スロットを使用するために必要

public:
    TristateCheckBoxExample(QWidget *parent = nullptr) : QWidget(parent)
    {
        setWindowTitle("三状態チェックボックスの例");
        setGeometry(100, 100, 350, 150);

        QVBoxLayout *layout = new QVBoxLayout(this);

        checkBox = new QCheckBox("サブオプション全て", this);
        // 三状態を有効にする
        checkBox->setTristate(true);
        // 初期状態を部分的にチェック済みに設定
        checkBox->setCheckState(Qt::PartiallyChecked);

        // stateChanged シグナルを接続
        // C++11 以降の新しい connect 記法 (ラムダ式も使える)
        connect(checkBox, &QCheckBox::stateChanged, this, &TristateCheckBoxExample::onCheckBoxStateChanged);

        layout->addWidget(checkBox);
    }

private slots:
    void onCheckBoxStateChanged(int state)
    {
        // Qt::CheckState 列挙型で状態を判定
        if (state == Qt::Checked) {
            qDebug() << "チェックボックスが完全にチェックされました。";
        } else if (state == Qt::Unchecked) {
            qDebug() << "チェックボックスがアンチェックされました。";
        } else if (state == Qt::PartiallyChecked) {
            qDebug() << "チェックボックスが部分的にチェックされました。";
        }
    }

private:
    QCheckBox *checkBox;
};

#include "main.moc" // moc_main.cpp を生成するための記述 (ファイル名に合わせて変更)

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    TristateCheckBoxExample window;
    window.show();
    return app.exec();
}

解説:

  • qDebug(): C++でのデバッグ出力に使用します。
  • connect(checkBox, &QCheckBox::stateChanged, this, &TristateCheckBoxExample::onCheckBoxStateChanged);: C++でのシグナル・スロット接続です。&QCheckBox::stateChanged でシグナルのポインタを渡し、&TristateCheckBoxExample::onCheckBoxStateChanged でスロットのポインタを渡します。
  • checkBox->setCheckState(Qt::PartiallyChecked);: 初期状態を「部分的にチェック済み」に設定しています。
  • checkBox->setTristate(true);: setTristate(true) を呼び出すことで、チェックボックスが3つの状態(Qt::Checked, Qt::Unchecked, Qt::PartiallyChecked)を持つようになります。

ビルドと実行 (C++):

  1. このコードを main.cpp として保存します。
  2. 同じディレクトリに main.h ファイルを作成し、上記のクラス定義(class TristateCheckBoxExample : public QWidget { ... } の部分)をコピーして貼り付け、インクルードガードを追加します。
    #ifndef TRISTATECHECKBOXEXAMPLE_H
    #define TRISTATECHECKBOXEXAMPLE_H
    
    #include <QWidget>
    #include <QCheckBox>
    
    class TristateCheckBoxExample : public QWidget
    {
        Q_OBJECT // シグナル/スロットを使用するために必要
    
    public:
        TristateCheckBoxExample(QWidget *parent = nullptr);
    
    private slots:
        void onCheckBoxStateChanged(int state);
    
    private:
        QCheckBox *checkBox;
    };
    
    #endif // TRISTATECHECKBOXEXAMPLE_H
    
  3. main.cpp の末尾に #include "main.moc" ではなく #include "TristateCheckBoxExample.moc" を追加し、TristateCheckBoxExample クラスの定義を TristateCheckBoxExample.h に移動させます。
  4. .pro ファイル (QMake) を作成します。
    QT       += widgets
    SOURCES  += main.cpp TristateCheckBoxExample.cpp
    HEADERS  += TristateCheckBoxExample.h
    
    (ここで、TristateCheckBoxExample.cpp にコンストラクタとスロットの実装を記述する必要があります。) または、単一の .cpp ファイルに全てを記述する場合は、Q_OBJECT を含むクラス定義をヘッダファイルに置き、.moc ファイルをインクルードする方法を正しく行う必要があります。

より簡単な単一ファイルでのC++ビルド方法(QMakeを使用しない場合):

# ヘッダファイルと同じ内容のクラス定義をmain.cppに直接記述し、
# Q_OBJECTマクロを使用する場合はmocを介してコンパイルする必要があります。
# 例:
# moc main.cpp -o moc_main.cpp
# g++ -fPIC -I/path/to/Qt/include -I/path/to/Qt/include/QtWidgets -o main main.cpp moc_main.cpp $(pkg-config --libs QtCore QtGui QtWidgets)

# 通常はQMakeやCMakeを使うのが標準的です。

QButtonGroup を使った排他的なチェックボックス (Python with PyQt/PySide)

複数のチェックボックスの中から一つだけを選択できるようにしたい場合(ラジオボタンのように)、QButtonGroup を使用します。

import sys
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QCheckBox, QButtonGroup, QGroupBox
from PyQt6.QtCore import Qt

class ExclusiveCheckBoxExample(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("排他的なチェックボックスの例")
        self.setGeometry(100, 100, 400, 200)

        main_layout = QVBoxLayout()
        self.setLayout(main_layout)

        # 視覚的なグループ化のために QGroupBox を使用
        country_group_box = QGroupBox("居住国を選択してください(一つだけ)")
        group_layout = QVBoxLayout()
        country_group_box.setLayout(group_layout)
        main_layout.addWidget(country_group_box)

        # 論理的なボタン(チェックボックス)グループを作成
        self.country_button_group = QButtonGroup(self)
        self.country_button_group.setExclusive(True) # 排他的選択を有効にする

        # チェックボックスを作成し、グループに追加
        countries = ["日本", "アメリカ", "カナダ", "その他"]
        for i, country in enumerate(countries):
            checkbox = QCheckBox(country)
            group_layout.addWidget(checkbox)
            self.country_button_group.addButton(checkbox, i) # ボタンとユニークなIDを追加

        # 初期選択
        self.country_button_group.buttons()[0].setChecked(True) # 最初のチェックボックスを初期選択

        # ボタンがクリックされたときのシグナルを接続
        self.country_button_group.buttonClicked.connect(self.on_country_selected)

    def on_country_selected(self, button):
        """QButtonGroup内のボタンがクリックされたときに呼び出されるスロット"""
        print(f"選択された国: {button.text()}")

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = ExclusiveCheckBoxExample()
    window.show()
    sys.exit(app.exec())

解説:

  • QGroupBox は、チェックボックスを視覚的にグループ化するために使用されます。
  • self.country_button_group.buttonClicked.connect(...): QButtonGroup は、グループ内のいずれかのボタンがクリックされたときに buttonClicked(QAbstractButton *button) シグナルを発行します。これにより、どのボタンがクリックされたかを直接知ることができます。
  • self.country_button_group.addButton(checkbox, i): 作成した各 QCheckBoxQButtonGroup に追加します。i は各ボタンに割り当てるユニークなIDです。
  • self.country_button_group.setExclusive(True): この設定が最も重要で、グループ内のチェックボックスがラジオボタンのように排他的に動作するようにします。つまり、どれか一つをチェックすると、他の全てのチェックボックスのチェックが自動的に外れます。
  • QButtonGroup(self): 新しいボタンの論理グループを作成します。


QCheckBoxが提供する「オン/オフ」または「三状態」の選択機能は非常に汎用性が高いですが、場合によっては他のウィジェットや実装パターンの方が適していることがあります。

ラジオボタン (QRadioButton)

代替となる場面:

  • QCheckBoxQButtonGroupと組み合わせて排他的な選択を実現することもできますが、見た目と意図の明確さから、最初からQRadioButtonを使用する方が自然です。
  • ユーザーに複数の選択肢の中から、厳密に一つだけを選ばせたい場合。

QRadioButtonの主な特徴:

  • 視覚的にも、丸いインジケータ(チェックボックスは四角)で排他的な選択であることを示します。
  • 同じQButtonGroupに属するQRadioButtonのグループでは、常に1つのボタンのみがチェック状態になります。

使用例:

import sys
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QRadioButton, QButtonGroup, QGroupBox

class RadioButtonExample(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("QRadioButton の例")
        self.setGeometry(100, 100, 300, 200)

        main_layout = QVBoxLayout()
        self.setLayout(main_layout)

        # 視覚的なグループ化
        genre_group_box = QGroupBox("好きなジャンルを選んでください")
        group_layout = QVBoxLayout()
        genre_group_box.setLayout(group_layout)
        main_layout.addWidget(genre_group_box)

        # 論理的なボタン(ラジオボタン)グループ
        self.genre_button_group = QButtonGroup(self)
        # QRadioButton はデフォルトで排他的 (setExclusive(True) は不要だが、明示しても良い)
        # self.genre_button_group.setExclusive(True)

        genres = ["SF", "ファンタジー", "ミステリー", "歴史"]
        for i, genre in enumerate(genres):
            radio_button = QRadioButton(genre)
            group_layout.addWidget(radio_button)
            self.genre_button_group.addButton(radio_button, i)

        # 初期選択
        self.genre_button_group.buttons()[0].setChecked(True)

        self.genre_button_group.buttonClicked.connect(self.on_genre_selected)

    def on_genre_selected(self, button):
        print(f"選択されたジャンル: {button.text()}")

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = RadioButtonExample()
    window.show()
    sys.exit(app.exec())

ドロップダウンリスト (QComboBox)

代替となる場面:

  • 選択肢が動的に変化する場合。
  • 画面スペースを節約したい場合。
  • 多数の選択肢の中から一つだけを選ばせたい場合。

QComboBoxの主な特徴:

  • テキスト入力も許可する(編集可能)設定も可能です。
  • コンパクトな表示で、クリックすると選択肢のリストが展開されます。

使用例:

import sys
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QComboBox, QLabel

class ComboBoxExample(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("QComboBox の例")
        self.setGeometry(100, 100, 300, 150)

        layout = QVBoxLayout()
        self.setLayout(layout)

        label = QLabel("都市を選択してください:")
        layout.addWidget(label)

        self.combo_box = QComboBox(self)
        self.combo_box.addItem("東京")
        self.combo_box.addItem("大阪")
        self.combo_box.addItem("名古屋")
        self.combo_box.addItem("福岡")

        # currentIndexChanged シグナルを接続
        # 引数として新しいインデックス (int) またはテキスト (str) を受け取るシグナルがある
        self.combo_box.currentIndexChanged.connect(self.on_city_selected)

        layout.addWidget(self.combo_box)

    def on_city_selected(self, index):
        selected_city = self.combo_box.currentText()
        print(f"選択された都市: {selected_city} (インデックス: {index})")

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = ComboBoxExample()
    window.show()
    sys.exit(app.exec())

リストウィジェット/ツリーウィジェット (QListWidget, QTreeWidget)

代替となる場面:

  • 各項目にアイコンや追加情報を持たせたい場合。
  • 階層的な選択が必要な場合(QTreeWidget)。
  • 複数の項目一覧表示し、その中から複数選択させたい場合。

QListWidget/QTreeWidgetの主な特徴:

  • チェックボックスが埋め込まれたアイテム (QListWidgetItem または QTreeWidgetItem) を作成し、それらの状態を管理できます。
  • setSelectionMode() メソッドで、単一選択 (QAbstractItemView.SingleSelection)、複数選択 (QAbstractItemView.MultiSelection, QAbstractItemView.ExtendedSelection) などを設定できます。

使用例 (QListWidget with checkboxes):

import sys
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QListWidget, QListWidgetItem
from PyQt6.QtCore import Qt

class ListWidgetCheckBoxExample(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("QListWidget とチェックボックスの例")
        self.setGeometry(100, 100, 350, 250)

        layout = QVBoxLayout()
        self.setLayout(layout)

        self.list_widget = QListWidget(self)
        layout.addWidget(self.list_widget)

        items = ["リンゴ", "バナナ", "オレンジ", "ブドウ", "イチゴ"]
        for item_text in items:
            list_item = QListWidgetItem(item_text)
            list_item.setFlags(list_item.flags() | Qt.ItemFlag.ItemIsUserCheckable) # チェック可能にする
            list_item.setCheckState(Qt.CheckState.Unchecked) # 初期状態は未チェック
            self.list_widget.addItem(list_item)

        # itemChanged シグナルを接続 (チェック状態が変更されたときにも発行される)
        self.list_widget.itemChanged.connect(self.on_list_item_changed)

    def on_list_item_changed(self, item):
        if item.checkState() == Qt.CheckState.Checked:
            print(f"{item.text()} がチェックされました。")
        else:
            print(f"{item.text()} がアンチェックされました。")

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = ListWidgetCheckBoxExample()
    window.show()
    sys.exit(app.exec())

ボタン (QPushButton) のトグル機能

代替となる場面:

  • テキストだけでなく、アイコンを大きく表示したい場合。
  • 見た目は通常のボタンだが、クリックするたびにオン/オフを切り替えたい場合。

QPushButtonの主な特徴:

  • toggled(bool) シグナルを発行します。
  • setChecked(bool) で状態を設定し、isChecked() で状態を取得できます。
  • setCheckable(True) を設定することで、ボタンがトグルボタンとして機能するようになります。

使用例:

import sys
from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton
from PyQt6.QtCore import Qt

class ToggleButtonExample(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("トグルボタンの例")
        self.setGeometry(100, 100, 300, 150)

        layout = QVBoxLayout()
        self.setLayout(layout)

        self.toggle_button = QPushButton("ミュート", self)
        self.toggle_button.setCheckable(True) # トグルボタンとして機能させる
        self.toggle_button.setChecked(False) # 初期状態はオフ

        # toggled シグナルを接続
        self.toggle_button.toggled.connect(self.on_button_toggled)

        layout.addWidget(self.toggle_button)

    def on_button_toggled(self, checked):
        if checked:
            print("ミュートが解除されました。")
            self.toggle_button.setText("ミュート解除")
        else:
            print("ミュートされました。")
            self.toggle_button.setText("ミュート")

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = ToggleButtonExample()
    window.show()
    sys.exit(app.exec())

カスタムウィジェット

代替となる場面:

  • 複雑なアニメーションや特殊なデータ表現をチェック状態と関連付けたい場合。
  • 標準のQCheckBoxの見た目や動作では実現できない、非常に特定のデザインやインタラクションが必要な場合。

主なアプローチ:

  • 独自のシグナルを定義し、外部に状態変化を通知します。
  • QPropertyAnimationなどを活用して、状態変化時のアニメーションを実現します。
  • mousePressEvent()などのイベントをハンドリングし、ユーザーの操作に応じて内部状態を更新し、update()を呼び出して再描画します。
  • QWidgetを継承し、paintEvent()をオーバーライドして、独自の描画ロジックを実装します。

これは最も高度な方法であり、標準ウィジェットで対応できない場合にのみ検討すべきです。