【保存版】Qt Widgetsでトグルボタンを駆使する:QAbstractButton::toggled()シグナルの使い方とサンプルコード


Qt WidgetsライブラリにおけるQAbstractButton::toggled()シグナルは、チェックボックスやラジオボタンなどのトグルボタンの状態変化を検知するために使用されます。このシグナルは、ボタンがクリックされたり、setChecked()メソッドでプログラム的に状態が変更されたり、排他制御グループ内の他のボタンが選択されたりしたときにemitされます。

シグナルの引数

toggled()シグナルは、bool型の引数checkedを持ちます。この引数は、ボタンの状態を表し、以下のいずれかの値になります。

  • false: ボタンがチェックされていない場合
  • true: ボタンがチェックされている場合

シグナルの接続

toggled()シグナルをスロットに接続するには、QObject::connect()関数を使用します。以下の例は、buttonという名前のボタンのtoggled()シグナルをmySlot()というスロットに接続する方法を示します。

connect(button, &QAbstractButton::toggled, this, &MyClass::mySlot);

シグナルのスロット

toggled()シグナルのスロットは、引数としてbool型の値を受け取ります。この値は、ボタンの状態を表します。スロット内で、この値を使用してボタンの状態に応じて処理を行うことができます。

以下の例は、toggled()シグナルを接続して、ボタンの状態に応じてラベルのテキストを変更する方法を示します。

class MyClass : public QObject
{
public:
    MyClass(QWidget *parent = nullptr);

private:
    QPushButton *button;
    QLabel *label;

public slots:
    void mySlot(bool checked);
};

MyClass::MyClass(QWidget *parent) : QObject(parent)
{
    button = new QPushButton(this);
    button->setText("Toggle");

    label = new QLabel(this);
    label->setText("Button is unchecked");

    connect(button, &QAbstractButton::toggled, this, &MyClass::mySlot);
}

void MyClass::mySlot(bool checked)
{
    if (checked) {
        label->setText("Button is checked");
    } else {
        label->setText("Button is unchecked");
    }
}

この例では、mySlot()スロットは、checked引数を使用してラベルのテキストを更新します。ボタンがチェックされた場合は "Button is checked" と表示し、チェックされていない場合は "Button is unchecked" と表示します。



#include <QApplication>
#include <QPushButton>
#include <QLabel>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QPushButton button("Toggle");
    QLabel label("Button is unchecked");

    button.connect(&button, &QPushButton::toggled, &label, &QLabel::setText);

    if (button.isChecked()) {
        label.setText("Button is checked");
    }

    button.show();
    label.show();

    return app.exec();
}

例2: トグルボタンのグループを制御する

この例は、toggled()シグナルを使用して、トグルボタンのグループを制御する方法を示します。

#include <QApplication>
#include <QRadioButton>
#include <QLabel>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QRadioButton option1("Option 1");
    QRadioButton option2("Option 2");
    QRadioButton option3("Option 3");

    QLabel selectedLabel;
    selectedLabel.setText("No option selected");

    option1.connect(&option1, &QRadioButton::toggled, &selectedLabel, &QLabel::setText);
    option2.connect(&option2, &QRadioButton::toggled, &selectedLabel, &QLabel::setText);
    option3.connect(&option3, &QRadioButton::toggled, &selectedLabel, &QLabel::setText);

    option1.setChecked(true);

    option1.show();
    option2.show();
    option3.show();
    selectedLabel.show();

    return app.exec();
}

例3: ボタンの状態に応じてアクションを実行する

この例は、toggled()シグナルを使用して、ボタンの状態に応じてアクションを実行する方法を示します。

#include <QApplication>
#include <QPushButton>
#include <QCheckBox>
#include <QFile>
#include <QMessageBox>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QPushButton openButton("Open File");
    QCheckBox enableButton("Enable");

    openButton.setEnabled(false);

    enableButton.connect(&enableButton, &QCheckBox::toggled, &openButton, &QPushButton::setEnabled);

    openButton.connect(&openButton, &QPushButton::clicked, []() {
        QFile file("myfile.txt");
        if (file.open(QIODevice::ReadOnly)) {
            QMessageBox::information(nullptr, "File Opened", "File opened successfully");
            file.close();
        } else {
            QMessageBox::warning(nullptr, "Error", "Unable to open file");
        }
    });

    enableButton.show();
    openButton.show();

    return app.exec();
}
  • 上記の例はあくまで基本的な使用方法を示しています。より複雑なシナリオには、追加のロジックやエラー処理が必要になる場合があります。


QCheckBox::stateChanged()シグナル

QCheckBoxの場合は、QAbstractButton::toggled()シグナルではなく、QCheckBox::stateChanged()シグナルを使用することを検討できます。このシグナルは、チェックボックスの状態が変化したときにemitされます。stateChanged()シグナルは、toggled()シグナルよりも汎用性が高く、チェックボックスがチェックされたかアンチェックされたかを区別できます。

利点

  • チェックされたかアンチェックされたかを区別できます。
  • チェックボックスの状態が変化したときにemitされます。

欠点

  • ラジオボタンには使用できません。


connect(checkBox, &QCheckBox::stateChanged, this, &MyClass::mySlot);

void MyClass::mySlot(int state)
{
    if (state == QCheckBox::Checked) {
        // チェックされた場合の処理
    } else {
        // アンチェックされた場合の処理
    }
}

QRadioButton::clicked()シグナル

QRadioButtonの場合は、QAbstractButton::toggled()シグナルではなく、QRadioButton::clicked()シグナルを使用することを検討できます。このシグナルは、ラジオボタンがクリックされたときにemitされます。clicked()シグナルは、ラジオボタンが選択されたことを明確に示すため、排他制御グループ内のボタンの状態を制御するのに役立ちます。

利点

  • ラジオボタンが選択されたことを明確に示します。
  • ラジオボタンがクリックされたときにemitされます。

欠点

  • チェックボックスには使用できません。


connect(radioButton, &QRadioButton::clicked, this, &MyClass::mySlot);

void MyClass::mySlot()
{
    // ラジオボタンが選択された場合の処理
}

タイマーを使用する

ボタンの状態を定期的にポーリングするタイマーを使用することもできます。この方法は、シグナルを使用するよりも効率が劣りますが、シグナルがemitされない状況で使用できます。

利点

  • シグナルがemitされない状況で使用できます。

欠点

  • ボタンの状態を定期的にポーリングする必要があるため、効率が劣ります。


timer = new QTimer(this);
timer->setInterval(100);
connect(timer, &QTimer::timeout, this, &MyClass::mySlot);

void MyClass::mySlot()
{
    if (button->isChecked()) {
        // ボタンがチェックされた場合の処理
    } else {
        // ボタンがアンチェックされた場合の処理
    }
}

カスタムシグナルを作成する

独自のニーズに合致するシグナルがない場合は、カスタムシグナルを作成することを検討できます。この方法は、より複雑なシナリオには適していますが、実装と使用がより複雑になります。

利点

  • 独自のニーズに合致するシグナルを作成できます。

欠点

  • 実装と使用がより複雑になります。


class MyButton : public QPushButton
{
public:
    signals:
        void toggledWithState(bool checked);

public slots:
    void clicked() override
    {
        emit toggledWithState(isChecked());
    }
};

connect(button, &MyButton::toggledWithState, this, &MyClass::mySlot);

void MyClass::mySlot(bool checked)
{
    // ボタンの状態に応じて処理を行う
}

QAbstractButton::toggled()シグナルは、トグルボタンの状態変化を検知するための便利なツールですが、状況によっては代替方法の方が適切な場合があります。上記の代替方法とその利点と欠点を考慮し、アプリケーションに最適な方法を選択してください。

  • 上記の代替方法はあくまで基本的な使用方法を示しています。より複雑なシナリオには、追加のロジックやエラー処理が必要になる場合があります。