【Qt入門】QSpinBox::textChanged()シグナルの使い方とプログラミング例

2025-05-31

これはQtのQSpinBoxクラスが持つシグナルです。

QSpinBoxは、数値の入力と表示を扱うウィジェットで、上下のボタンやキーボード操作、直接テキスト入力によって値を変更できます。

textChanged(const QString &text)シグナルは、QSpinBoxに表示されているテキストが変更されたときに発行されます。このシグナルには、変更後のテキストがQString型の引数textとして渡されます。

主な特徴と用途

  • 引数: 変更後のテキスト全体(プレフィックスとサフィックスを含む)がconst QString &textとして渡されます。
  • valueChanged()との違い:
    • valueChanged(int value)(またはQDoubleSpinBoxの場合はvalueChanged(double value))は、数値としての値が変更されたときに発行されます。
    • textChanged(const QString &text)は、表示されるテキストが変更されたときに発行されます。例えば、プレフィックスやサフィックスが設定されている場合、値自体は同じでも、表示形式が変わるとtextChanged()が発行されることがあります。また、ユーザーが値を入力中に1文字ずつ入力するたびにtextChanged()が発行されます。
  • テキストの変化を通知: QSpinBoxの表示内容(プレフィックス、サフィックスを含む)がユーザーの操作(ボタンクリック、キーボード入力)によって変更されたり、プログラム的にsetValue()などで値が変更されたりした場合にこのシグナルが発行されます。

使用例

このシグナルは、例えば以下のような場合に役立ちます。

  • ログ記録: QSpinBoxのテキスト変更履歴を記録したい場合。
  • 関連するUI要素の更新: QSpinBoxの表示テキストに基づいて、他のウィジェットの表示を更新したり、特定の処理を実行したりする場合。
  • 入力のリアルタイム検証: ユーザーがQSpinBoxにテキストを入力するたびに、その入力内容をリアルタイムで検証し、有効な形式であるか、特定の条件を満たしているかなどをチェックしたい場合。
#include <QApplication>
#include <QSpinBox>
#include <QLabel>
#include <QVBoxLayout>

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

    QWidget window;
    QVBoxLayout *layout = new QVBoxLayout(&window);

    QSpinBox *spinBox = new QSpinBox(&window);
    spinBox->setRange(0, 100);
    spinBox->setPrefix("Value: ");
    spinBox->setSuffix(" units");
    spinBox->setValue(50);

    QLabel *displayLabel = new QLabel("Current text: ", &window);

    // textChanged シグナルとカスタムスロットを接続
    QObject::connect(spinBox, &QSpinBox::textChanged,
                     [displayLabel](const QString &text){
                         displayLabel->setText("Current text: " + text);
                     });

    layout->addWidget(spinBox);
    layout->addWidget(displayLabel);

    window.setLayout(layout);
    window.setWindowTitle("QSpinBox textChanged Example");
    window.show();

    return app.exec();
}


シグナルが意図せず頻繁に発行される

問題: ユーザーがQSpinBoxに数値を入力している最中(例: 「1」と入力してから「2」と入力して「12」となるまで)に、textChanged()シグナルが入力のたびに発行され、接続されたスロットが何度も呼ばれてしまう。これにより、重い処理をスロットで行っている場合、パフォーマンスが低下することがあります。

原因: textChanged()は、文字が1つでも変更されるたびに発行されます。ユーザーが「1」「2」「3」と入力すると、「1」「12」「123」の3回シグナルが発行されます。

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

  • タイマーによるデバウンス: 短時間に連続してシグナルが発行されるのを避けたい場合、スロット内でQTimer::singleShot()を使って遅延処理を行う「デバウンス」という手法を用いることができます。例えば、シグナルが発行されたらタイマーを開始し、タイマーがタイムアウトする前に再度シグナルが発行されたらタイマーをリセットするという方法です。
  • QSpinBox::setKeyboardTracking(false) を設定する: QSpinBoxsetKeyboardTracking(false)を設定すると、ユーザーがキーボードで入力している間はvalueChanged()textChanged()シグナルは発行されず、Enterキーを押すか、フォーカスが外れたときにのみ発行されるようになります。ただし、上下ボタンによる変更では引き続きリアルタイムでシグナルが発行されます。
  • editingFinished() シグナルの利用を検討する: ユーザーが入力の完了(Enterキーを押す、フォーカスが外れるなど)を待って処理を実行したい場合は、QAbstractSpinBox::editingFinished() シグナルを使用するのが適切です。これは、編集が完了したときにのみ発行されます。

valueChanged() と textChanged() の違いを混同している

問題: 数値が変更されたときにのみ処理を行いたいのに、textChanged()シグナルを使用しているため、プレフィックスやサフィックスの変更など、数値以外のテキスト変更でもスロットが呼ばれてしまう。

原因:

  • textChanged(const QString &text): QSpinBoxに表示されているテキスト全体が変更されたときに発行されます。これには、プレフィックス、サフィックス、特殊な値のテキストも含まれます。
  • valueChanged(int value) / valueChanged(double value): 数値が変更されたときに発行されます。プレフィックスやサフィックスの変更では発行されません。

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

  • 目的に合ったシグナルを選択する:
    • 数値の変化に反応したい場合: valueChanged()シグナルを使用してください。
    • 表示されているテキストの全体的な変化に反応したい場合: textChanged()シグナルを使用してください。特に、prefix()suffix()specialValueText()などを利用していて、それらの影響を受けた表示テキストの変化を監視したい場合に有用です。

プログラムによる値の変更でもシグナルが発行される

問題: setValue()などを用いてプログラム的にQSpinBoxの値を変更した場合にもtextChanged()シグナルが発行され、意図しない処理が実行されてしまう。

原因: textChanged()シグナルは、ユーザー操作だけでなく、setValue()などのプログラム的な操作によってもQSpinBoxの表示テキストが変更されれば発行されます。

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

  • フラグを用いる: スロット内で、値がプログラム的に変更されたかどうかを示すブール型フラグをチェックする方法もあります。

    bool m_isProgrammaticChange = false; // メンバー変数として定義
    
    void MyClass::on_spinBox_textChanged(const QString &text) {
        if (m_isProgrammaticChange) {
            return; // プログラム的な変更なので処理をスキップ
        }
        // ユーザーによる変更時の処理
        qDebug() << "User changed text to: " << text;
    }
    
    void MyClass::setSpinBoxValueProgrammatically(int value) {
        m_isProgrammaticChange = true;
        ui->spinBox->setValue(value);
        m_isProgrammaticChange = false;
    }
    

    この方法は、blockSignals()よりも柔軟性がありますが、フラグの管理が複雑になる可能性があります。

  • QObject::blockSignals() を使用する: シグナルを発行させたくない処理を行う直前にspinBox->blockSignals(true);を呼び出し、処理完了後にspinBox->blockSignals(false);を呼び出すことで、その間のシグナル発行を一時的にブロックできます。

    spinBox->blockSignals(true); // シグナル発行をブロック
    spinBox->setValue(123);     // この変更ではtextChanged()は発行されない
    spinBox->blockSignals(false); // シグナル発行を再開
    

テキストのパースエラーや不正な入力の処理

問題: textChanged()シグナルは生のテキストを渡すため、ユーザーがまだ入力途中の不完全なテキストや、数値として無効なテキスト(例: "abc")を入力した場合に、接続されたスロットでのパース処理が失敗したり、エラーが発生したりする。

原因: QSpinBoxは、最終的な値が範囲内であるか、または数値として有効であるかを内部的に検証しますが、textChanged()はそうした検証前の途中のテキストも提供します。

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

  • 正規表現での検証: より複雑な入力形式を検証したい場合は、QRegExpValidatorQRegularExpressionValidatorを使用してQSpinBoxの入力を制限したり、textChanged()スロット内で正規表現を用いてテキストを検証したりします。

  • cleanText() の利用: QSpinBox::cleanText() メソッドは、プレフィックス、サフィックス、空白を含まない、純粋な数値部分のテキストを返します。これにより、パース処理を簡素化できる場合があります。

  • 入力検証とエラーハンドリング: スロット内で受け取ったQStringtoInt()(またはtoDouble())で数値に変換する前に、bool *ok = nullptr;を引数に渡し、変換が成功したかどうかを確認するようにします。

    void MyClass::on_spinBox_textChanged(const QString &text) {
        bool ok;
        int value = text.toInt(&ok); // 文字列から数値に変換
    
        if (ok) {
            // 有効な数値に変換できた場合の処理
            qDebug() << "Valid number entered: " << value;
            // 例: 他のUI要素を更新
        } else {
            // 無効なテキストの場合の処理(例: エラー表示、デフォルト値に戻すなど)
            qDebug() << "Invalid text entered: " << text;
            // 例: ユーザーに警告メッセージを表示
        }
    }
    

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

問題: textChanged()シグナルがまったく発行されない、またはスロットが呼ばれない。

原因: シグナルとスロットの接続が正しく行われていない可能性があります。

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

  • オブジェクトのライフサイクル: QSpinBoxオブジェクトや、スロットを持つオブジェクトが正しく生成され、破棄されていないか確認します。接続が確立される前にオブジェクトが破棄されてしまうと、シグナルは発行されません。

  • qDebug() を使用してデバッグ: シグナルが発行されているか、スロットが呼び出されているかをqDebug()文を挿入して確認します。

    // シグナルが発行されたときに表示
    void MyClass::on_spinBox_textChanged(const QString &text) {
        qDebug() << "textChanged signal emitted with text: " << text;
        // ...
    }
    
  • 接続構文の確認: 最新のQtでは、関数ポインタ構文が推奨されます。

    // 推奨される新しい構文
    QObject::connect(spinBox, &QSpinBox::textChanged,
                     this, &MyClass::on_spinBox_textChanged);
    
    // 古い文字列構文 (非推奨だがまだ動作する)
    // QObject::connect(spinBox, SIGNAL(textChanged(QString)),
    //                  this, SLOT(on_spinBox_textChanged(QString)));
    

    特に引数の型(const QString &)が一致しているか確認してください。



以下に、textChanged()シグナルのプログラミング例をいくつか示します。

基本的な使用例:テキストの変更をリアルタイムで表示する

この例では、QSpinBoxのテキストが変更されるたびに、その内容をQLabelに表示します。

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

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

public:
    MyWidget(QWidget *parent = nullptr) : QWidget(parent)
    {
        // QSpinBoxの作成
        QSpinBox *spinBox = new QSpinBox(this);
        spinBox->setRange(0, 100);       // 0から100までの範囲を設定
        spinBox->setPrefix("Value: ");   // プレフィックスを設定
        spinBox->setSuffix(" units");    // サフィックスを設定
        spinBox->setValue(50);          // 初期値を設定

        // テキスト表示用のQLabelの作成
        QLabel *displayLabel = new QLabel("Current text: ", this);

        // QSpinBoxのtextChangedシグナルをQLabelのsetTextスロットに接続
        // ラムダ式を使用して、変更されたテキストをQLabelに設定
        QObject::connect(spinBox, &QSpinBox::textChanged,
                         displayLabel, [displayLabel](const QString &text){
            displayLabel->setText("Current text: " + text);
            qDebug() << "Text changed to: " << text; // デバッグ出力
        });

        // レイアウトの作成
        QVBoxLayout *layout = new QVBoxLayout(this);
        layout->addWidget(spinBox);
        layout->addWidget(displayLabel);
        setLayout(layout);

        setWindowTitle("QSpinBox textChanged Example");
    }
};

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

    MyWidget w;
    w.show();

    return a.exec();
}

#include "main.moc" // mocファイルを含める (Qt Creatorを使用している場合は通常自動生成されます)

説明:

  • prefix()suffix()が設定されているため、textChanged()で受け取るtextはそれらを含んだ文字列になります(例: "Value: 50 units")。
  • ユーザーがQSpinBoxの値を変更すると(数字を入力、上下ボタンクリックなど)、即座にQLabelの表示が更新され、デバッグコンソールにもテキストが出力されます。
  • QSpinBoxtextChanged(const QString &text)シグナルを、ラムダ式を使用してQLabelのテキストを更新するスロットに接続しています。

入力途中のテキストを検証する例

textChanged()は入力のたびに呼ばれるため、入力途中のテキストを検証するのに使えます。ここでは、入力が有効な数値であるかをチェックし、結果に応じて表示を切り替えます。

#include <QApplication>
#include <QWidget>
#include <QSpinBox>
#include <QLabel>
#include <QVBoxLayout>
#include <QMessageBox> // メッセージボックス用
#include <QDebug>

class InputValidationWidget : public QWidget
{
    Q_OBJECT

public:
    InputValidationWidget(QWidget *parent = nullptr) : QWidget(parent)
    {
        QSpinBox *spinBox = new QSpinBox(this);
        spinBox->setRange(0, 1000);
        spinBox->setValue(100);

        QLabel *statusLabel = new QLabel("Enter a number:", this);
        statusLabel->setStyleSheet("color: black;"); // デフォルトの色

        QVBoxLayout *layout = new QVBoxLayout(this);
        layout->addWidget(spinBox);
        layout->addWidget(statusLabel);
        setLayout(layout);

        // textChanged シグナルをカスタムスロットに接続
        QObject::connect(spinBox, &QSpinBox::textChanged,
                         this, &InputValidationWidget::onSpinBoxTextChanged);

        setWindowTitle("Input Validation Example");
    }

private slots:
    void onSpinBoxTextChanged(const QString &text)
    {
        QLabel *statusLabel = findChild<QLabel*>(); // QLabelを取得 (実際のコードではメンバー変数を使うのが一般的)

        bool ok;
        int value = text.toInt(&ok); // 文字列を数値に変換

        if (ok) {
            // 有効な数値の場合
            statusLabel->setText("Valid number: " + QString::number(value));
            statusLabel->setStyleSheet("color: green;");
            qDebug() << "Valid: " << value;
        } else {
            // 無効なテキストの場合
            statusLabel->setText("Invalid input: Not a number or incomplete.");
            statusLabel->setStyleSheet("color: red;");
            qDebug() << "Invalid: " << text;
        }
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    InputValidationWidget w;
    w.show();
    return a.exec();
}

#include "main.moc"

説明:

  • oktrueなら緑色の「Valid number」メッセージを、falseなら赤色の「Invalid input」メッセージを表示します。これにより、ユーザーはリアルタイムで入力の有効性を確認できます。
  • 変換が成功したかどうかの結果は ok ブール変数に格納されます。
  • onSpinBoxTextChanged スロット内で、text.toInt(&ok) を使って、入力されたテキストが整数に変換可能かをチェックしています。

プログラムによる値の変更時にシグナル発行をブロックする例

setValue()などでプログラム的に値を変更した場合にtextChanged()シグナルが発行されるのを避けたい場合があります。QObject::blockSignals()を使用することでこれを制御できます。

#include <QApplication>
#include <QWidget>
#include <QSpinBox>
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>
#include <QDebug>

class BlockSignalsExample : public QWidget
{
    Q_OBJECT

public:
    BlockSignalsExample(QWidget *parent = nullptr) : QWidget(parent)
    {
        spinBox = new QSpinBox(this);
        spinBox->setRange(0, 200);
        spinBox->setValue(100);

        QLabel *infoLabel = new QLabel("Check debug output for text changes.", this);

        QPushButton *setValueButton = new QPushButton("Set Value Programmatically to 75", this);

        QVBoxLayout *layout = new QVBoxLayout(this);
        layout->addWidget(spinBox);
        layout->addWidget(infoLabel);
        layout->addWidget(setValueButton);
        setLayout(layout);

        // spinBoxのtextChangedシグナルをスロットに接続
        QObject::connect(spinBox, &QSpinBox::textChanged,
                         this, &BlockSignalsExample::onSpinBoxTextChanged);

        // ボタンがクリックされたら値をプログラム的に設定するスロットに接続
        QObject::connect(setValueButton, &QPushButton::clicked,
                         this, &BlockSignalsExample::onSetValueButtonClicked);

        setWindowTitle("Block Signals Example");
    }

private slots:
    void onSpinBoxTextChanged(const QString &text)
    {
        qDebug() << "textChanged signal emitted: " << text;
    }

    void onSetValueButtonClicked()
    {
        qDebug() << "Setting value programmatically...";
        // シグナル発行を一時的にブロック
        spinBox->blockSignals(true);
        spinBox->setValue(75); // このsetValue()ではtextChanged()は発行されない
        spinBox->blockSignals(false); // シグナル発行を再開
        qDebug() << "Value set. Signals re-enabled.";

        // シグナルブロックなしでsetValue()を呼び出した場合
        // spinBox->setValue(76); // この場合、textChanged()が発行される
    }

private:
    QSpinBox *spinBox;
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    BlockSignalsExample w;
    w.show();
    return a.exec();
}

#include "main.moc"

説明:

  • この例を実行し、ボタンをクリックすると、onSpinBoxTextChangedは呼ばれないことがデバッグ出力で確認できます。しかし、ユーザーが直接QSpinBoxの値を変更すると、シグナルが発行されます。
  • 値の設定が完了したら、spinBox->blockSignals(false); を呼び出してシグナル発行を再度有効にします。
  • onSetValueButtonClicked() スロット内で、spinBox->blockSignals(true); を呼び出すことで、その後のsetValue()呼び出しによるtextChanged()シグナルの発行を一時的に停止しています。


ここでは、textChanged()シグナルに代わる、または補完する一般的な方法をいくつか説明します。

QSpinBox::valueChanged(int value) / QDoubleSpinBox::valueChanged(double value)

これはQSpinBox::textChanged() の最も直接的な代替であり、多くの場合、より適切です。

  • 利用ケース:

    • QSpinBoxが表す数値そのものの変化にのみ関心がある場合。
    • 表示テキストの書式(プレフィックス、サフィックス、区切り文字など)に関わらず、数値の変化に応じてロジックを実行したい場合。
    • テキストがユーザーによって少しずつ入力されるたびに処理を実行したくない場合(入力完了後に処理したい場合)。
  • 違い:

    • textChanged() は、QSpinBoxに表示されるテキスト全体が変更されたときに発行されます(プレフィックス、サフィックスを含む)。ユーザーが「1」と入力してから「2」と入力して「12」となるまで、それぞれ「1」、「12」でシグナルが発行されます。
    • valueChanged() は、QSpinBoxが保持する数値としての値が変更されたときに発行されます。プレフィックスやサフィックスの変更では発行されません。また、ユーザーが「1」と入力し、次に「2」と入力して「12」となった場合、数値が「1」から「12」に変わったときにのみ発行されます。ユーザーが「12」と入力している途中で「1」の段階では値が確定していないため、通常、「12」となった時点で発行されます。


#include <QApplication>
#include <QWidget>
#include <QSpinBox>
#include <QLabel>
#include <QVBoxLayout>
#include <QDebug>

class ValueChangedExample : public QWidget
{
    Q_OBJECT
public:
    ValueChangedExample(QWidget *parent = nullptr) : QWidget(parent)
    {
        QSpinBox *spinBox = new QSpinBox(this);
        spinBox->setRange(0, 100);
        spinBox->setPrefix("Num: ");
        spinBox->setSuffix(" pcs");
        spinBox->setValue(25);

        QLabel *displayLabel = new QLabel("Current value: ", this);

        // valueChanged シグナルを接続
        QObject::connect(spinBox, &QSpinBox::valueChanged,
                         displayLabel, [displayLabel](int value){
            displayLabel->setText(QString("Current value: %1").arg(value));
            qDebug() << "Value changed to: " << value; // 値の変更時のみ出力
        });

        QVBoxLayout *layout = new QVBoxLayout(this);
        layout->addWidget(spinBox);
        layout->addWidget(displayLabel);
        setLayout(layout);
        setWindowTitle("QSpinBox valueChanged Example");
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    ValueChangedExample w;
    w.show();
    return a.exec();
}
#include "main.moc"

textChanged()との動作比較

  • valueChanged()
    ユーザーが「1」と入力し、次に「2」を入力して「12」と確定すると、数値が変更されたと認識され「12」でシグナル(途中の「1」では通常発行されない)。上下ボタンで変更した場合も、値が変化するたびに発行。
  • textChanged()
    ユーザーが「1」と入力すると「Num: 1 pcs」でシグナル、次に「2」を入力して「Num: 12 pcs」でシグナル。

QAbstractSpinBox::editingFinished()

QSpinBoxQAbstractSpinBoxから派生しており、editingFinished()シグナルを提供します。

  • 利用ケース:

    • ユーザーが手動でテキストを入力し、その入力を確定した時点で処理を実行したい場合。
    • 入力途中でのリアルタイム検証は不要で、最終的な入力値に基づいて処理を行いたい場合。
    • textChanged()valueChanged()が頻繁に発行されるのを避け、処理の実行回数を減らしたい場合。
  • 特徴:

    • ユーザーがスピンボックスの編集を終えたときに発行されます。具体的には、Enterキーを押す、またはスピンボックスがフォーカスを失ったときです。
    • 上下ボタンによる値の変更では発行されません


#include <QApplication>
#include <QWidget>
#include <QSpinBox>
#include <QLabel>
#include <QVBoxLayout>
#include <QDebug>

class EditingFinishedExample : public QWidget
{
    Q_OBJECT
public:
    EditingFinishedExample(QWidget *parent = nullptr) : QWidget(parent)
    {
        QSpinBox *spinBox = new QSpinBox(this);
        spinBox->setRange(0, 1000);
        spinBox->setValue(100);

        QLabel *resultLabel = new QLabel("Ready for input...", this);

        // editingFinished シグナルを接続
        QObject::connect(spinBox, &QSpinBox::editingFinished,
                         this, [spinBox, resultLabel](){
            int finalValue = spinBox->value(); // 確定した値を取得
            resultLabel->setText(QString("Input finished. Final value: %1").arg(finalValue));
            qDebug() << "Editing finished. Final value: " << finalValue;
        });

        QVBoxLayout *layout = new QVBoxLayout(this);
        layout->addWidget(spinBox);
        layout->addWidget(resultLabel);
        setLayout(layout);
        setWindowTitle("QSpinBox editingFinished Example");
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    EditingFinishedExample w;
    w.show();
    return a.exec();
}
#include "main.moc"

説明:

  • 上下ボタンをクリックしてもこのシグナルは発行されないため、その点は注意が必要です。
  • ユーザーがQSpinBoxに手動で値を入力し、Enterキーを押すか、他のウィジェットをクリックしてフォーカスを外すと、editingFinished()シグナルが発行されます。

QSpinBox::setKeyboardTracking(bool enable) の利用

これはシグナル自体ではありませんが、textChanged()valueChanged()発行タイミングを制御する上で非常に重要です。

  • 利用ケース:
    • ユーザーがキーボードで数値を入力している間、リアルタイムでの処理は不要で、入力が完了したと判断できる時点で処理を行いたい場合。
    • パフォーマンスの最適化のために、シグナルの発行回数を減らしたい場合。
  • 設定: spinBox->setKeyboardTracking(false);


(1.のvalueChangedの例にsetKeyboardTracking(false)を追加)

#include <QApplication>
#include <QWidget>
#include <QSpinBox>
#include <QLabel>
#include <QVBoxLayout>
#include <QDebug>

class KeyboardTrackingExample : public QWidget
{
    Q_OBJECT
public:
    KeyboardTrackingExample(QWidget *parent = nullptr) : QWidget(parent)
    {
        QSpinBox *spinBox = new QSpinBox(this);
        spinBox->setRange(0, 100);
        spinBox->setValue(25);
        spinBox->setKeyboardTracking(false); // ★ここを追加!

        QLabel *displayLabel = new QLabel("Current value: ", this);

        QObject::connect(spinBox, &QSpinBox::valueChanged,
                         displayLabel, [displayLabel](int value){
            displayLabel->setText(QString("Current value: %1").arg(value));
            qDebug() << "Value changed to: " << value;
        });

        QVBoxLayout *layout = new QVBoxLayout(this);
        layout->addWidget(spinBox);
        layout->addWidget(displayLabel);
        setLayout(layout);
        setWindowTitle("QSpinBox Keyboard Tracking Example");
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    KeyboardTrackingExample w;
    w.show();
    return a.exec();
}
#include "main.moc"

説明:

  • ただし、上下ボタンをクリックした場合は、setKeyboardTracking(false)を設定していても、値の変更ごとにシグナルが発行されます。
  • 入力後にEnterキーを押すか、フォーカスを外すと、最終的な値(例: 123)でvalueChanged()が1回だけ発行されます。
  • この例では、ユーザーがキーボードで「1」「2」「3」と入力しても、各文字でtextChanged()valueChanged()は発行されません。

QSpinBoxのQLineEdit部分にアクセスする(非推奨/高度なケース)

QSpinBoxは内部にQLineEditを持っており、lineEdit()メソッドでそのポインタを取得できます。QLineEdittextChanged()シグナルとは別にtextEdited()シグナルを持っています。

  • 利用ケース:

    • ユーザーがキーボードで入力した生テキスト(プレフィックス、サフィックスなし)のみに反応したい場合。
    • プログラム的な変更とユーザー操作を厳密に区別したい場合。
    • ただし、QSpinBoxの通常の数値処理ロジックをバイパスする可能性があるため、注意が必要です。QSpinBoxの設計意図から逸脱する可能性があるため、通常は避けるべきです。
  • QLineEdit::textEdited(const QString &text):

    • これはユーザーの操作によってのみテキストが変更されたときに発行されます。
    • QLineEdit::setText()のようなプログラム的な変更では発行されません。
    • QSpinBoxの場合、textChanged()はプログラム的なsetValue()でも発行されるため、ユーザー操作のみを区別したい場合にQLineEdit::textEdited()が役立つことがあります。


#include <QApplication>
#include <QWidget>
#include <QSpinBox>
#include <QLabel>
#include <QVBoxLayout>
#include <QLineEdit> // QLineEditを使用
#include <QDebug>

class LineEditTextEditedExample : public QWidget
{
    Q_OBJECT
public:
    LineEditTextEditedExample(QWidget *parent = nullptr) : QWidget(parent)
    {
        QSpinBox *spinBox = new QSpinBox(this);
        spinBox->setRange(0, 100);
        spinBox->setValue(50);

        QLabel *displayLabel = new QLabel("Raw text entered: ", this);

        // QSpinBoxの内部のQLineEditにアクセス
        QLineEdit *lineEdit = spinBox->lineEdit();
        if (lineEdit) {
            // QLineEditのtextEditedシグナルを接続
            QObject::connect(lineEdit, &QLineEdit::textEdited,
                             displayLabel, [displayLabel](const QString &text){
                displayLabel->setText("Raw text entered: " + text);
                qDebug() << "LineEdit text edited to: " << text;
            });
        } else {
            qWarning() << "Could not get QLineEdit from QSpinBox!";
        }


        QVBoxLayout *layout = new QVBoxLayout(this);
        layout->addWidget(spinBox);
        layout->addWidget(displayLabel);
        setLayout(layout);
        setWindowTitle("QSpinBox internal QLineEdit textEdited Example");
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    LineEditTextEditedExample w;
    w.show();
    return a.exec();
}
#include "main.moc"

説明:

  • この方法は、QSpinBoxが提供する数値処理のロジック(範囲チェックなど)とは独立して、純粋なテキスト入力の変化を監視したい場合に検討できます。
  • QLineEdittextEdited()シグナルに接続することで、ユーザーが入力した生のテキスト(プレフィックスやサフィックスを含まない)がリアルタイムで取得できます。
  • spinBox->lineEdit()で内部のQLineEditにアクセスしています。

QSpinBox::textChanged()はテキストのあらゆる変更に反応するため非常に強力ですが、多くの場合は以下の代替・補完方法がより適切です。

  • ユーザーの生テキスト入力のみに反応したい(高度なケース): 内部のQLineEdit()を取得し、そのtextEdited()シグナルを使う。
  • キーボード入力中の頻繁なシグナル発行を避けたい: QSpinBox::setKeyboardTracking(false) を設定する。
  • 入力確定時にのみ反応したい: QAbstractSpinBox::editingFinished() を使う。
  • 数値の変化に反応したい: QSpinBox::valueChanged(int value) を使う。