Qt

【C++】QtのQSpinBoxで実現する直感的な整数入力ウィジェットの基本操作とカスタマイズ例

QtのQSpinBoxは整数入力用のウィジェットで、直感的に値の増減が行えます。

setRangeで最小・最大値を、setSingleStepで変化量を指定でき、setPrefixsetSuffixで表示をカスタマイズできます。

シンプルな実装で操作性の良いユーザーインターフェースを実現できる点が魅力です。

QSpinBoxの基本機能

QSpinBoxの役割と特徴

QSpinBoxは、ユーザーが整数値を直感的に入力・選択できるウィジェットです。

ウィジェットには上下の矢印ボタンが備わっており、数値を簡単に増減できるため、手動入力と合わせてとても使いやすい仕組みになっています。

複雑な数値入力を求める場面ではなく、あくまで基本的な整数の選択に適していて、簡単な設定で利用できる点が魅力です。

また、QSpinBoxは、入力値の範囲やステップ幅、プレフィックス・サフィックスなどの表示を柔軟に変更できるため、ユーザーが扱うデータに合わせたカスタマイズが可能です。

さまざまなシーンでの利用が想定されるため、プログラムに統一感を持たせたい場合にも適しています。

数値入力ウィジェットとしての動作

QSpinBoxは、ユーザーの入力に応じて自動的に数値を調整する機能が備わっているため、数値入力部分を自分で実装する必要がありません。

例えば、上下の矢印ボタンで値を一つずつ増減できる仕組みや、キーボードで矢印キーを使って操作できる点など、ユーザーにとって分かりやすく使いやすい動作を実現しています。

数値が限定されている場合でも、適切な範囲内での入力を保証してくれるため、入力ミスを軽減する効果が期待できます。

基本操作とプロパティ設定

値の範囲と初期値設定

QSpinBoxは、表示する値の範囲や初期値の設定が簡単にできる点が魅力です。

ユーザーが間違った値を入力しないように、最小値と最大値を設定することで安全に利用できます。

以下の項目で、基本的なプロパティ設定の方法について説明します。

setRangeによる最小・最大値の定義

setRangeメソッドを利用すると、ウィジェットで扱うことができる数値の最小値と最大値を同時に設定できます。

例えば、0から100までの値に限定する場合、以下のようなコードで設定します。

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

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

    QSpinBox *spinBox = new QSpinBox(&window);
    spinBox->setRange(0, 100);
    spinBox->setMinimumWidth(100);  // 幅を広げる

    QVBoxLayout *layout = new QVBoxLayout(&window);
    layout->addWidget(spinBox);

    window.setLayout(layout);
    window.show();

    return app.exec();
}
// アプリケーション起動後、0~100の範囲内で値を操作できるウィジェットが表示されます

このコードは、ウィジェット上に0から100までの数値を入力できるQSpinBoxを作成しています。

ユーザーが矢印ボタンをクリックするたびに、設定した範囲内で数値が調整されます。

setValueによる初期値の設定

ウィジェットが表示されたときに、初期値として特定の数値を設定したい場合はsetValueメソッドを使います。

以下の例では、初期値を50に設定しています。

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

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

    QSpinBox spinBox(&window);
    spinBox.setRange(0, 100);
    spinBox.setMinimumWidth(100);
    spinBox.setValue(50);         // 初期値を50に設定

    QVBoxLayout *layout = new QVBoxLayout(&window);
    layout->addWidget(&spinBox);

    window.setLayout(layout);
    window.show();

    return app.exec();
}
// ウィジェット表示時、初期値50が入力された状態で表示されます

このように、setValueを使うことで特定の初期値を容易に設定でき、ユーザーが直感的にその範囲で調整を開始できるようになります。

ステップ幅の設定

setSingleStepの活用方法

QSpinBoxでは、値を上下に調整する際の増減量(ステップ幅)をsetSingleStepで変更できます。

例えば、増減量を5に設定すると、ユーザーが矢印ボタンを押すたびに、数値が5ずつ変動します。

以下はそのサンプルコードです。

#include <QApplication>
#include <QSpinBox>
#include <QWidget>
int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    QWidget window;
    QSpinBox spinBox(&window);
    spinBox.setMinimumWidth(100);
    spinBox.setRange(0, 100);        // 範囲設定
    spinBox.setSingleStep(5);        // ステップ幅を5に設定
    spinBox.setValue(20);            // 初期値を20に設定
    window.show();
    return app.exec();
}
// 矢印ボタンを操作すると、数値が5ずつ増減する動作が確認できます

このコードにより、ユーザーが少しずつ大きな変化を求める場面でも、一定の間隔で数値を変更できるため、調整がしやすくなります。

表示カスタマイズ

setPrefixでのプレフィックス設定

setPrefixメソッドを使うと、数値の前に任意の文字列を表示することができます。

たとえば、通貨記号を表示する場合は$を設定すれば、数値が「$50」のように表示されるようになります。

プレフィックスを設定すると、表示内容に統一感が生まれ、ユーザーに数値の種類を直感的に伝えることができます。

#include <QApplication>
#include <QSpinBox>
#include <QWidget>
int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    QWidget window;
    QSpinBox spinBox(&window);
    spinBox.setMinimumWidth(100);
    spinBox.setRange(0, 100);
    spinBox.setValue(30);
    spinBox.setPrefix("$");  // 数値の前に"$"を表示
    window.show();
    return app.exec();
}
// 表示される数値の左側に"$"が追加されて、「$30」等の形式で表示されます

setSuffixでのサフィックス設定

同様に、setSuffixメソッドでは、数値の後ろに文字列を追加することができます。

例えば、温度を示す場合に「°C」を付与するなどの用途で利用できます。

これにより、ユーザーには入力される数値が何を表しているかが一目で分かるようになります。

#include <QApplication>
#include <QSpinBox>
#include <QWidget>
int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    QWidget window;
    QSpinBox spinBox(&window);
    spinBox.setMinimumWidth(100);
    spinBox.setRange(-50, 50);
    spinBox.setValue(0);
    spinBox.setSuffix(" °C");  // 数値の後に" °C"を表示
    window.show();
    return app.exec();
}
// 数値の右側に" °C"が表示され、「0 °C」などの形で表現されます

シグナルとイベント処理

値変更シグナルの利用

valueChangedシグナルの概要

QSpinBoxは、値が変更されたときにvalueChangedシグナルを送出する仕組みがあり、これを利用して他のウィジェットとの連動や内部処理の更新が可能です。

値が変わるたびに自動で通知されるため、例えばリアルタイムの計算や表示更新に活用できます。

シグナルとスロットの仕組みを利用することで、ウィジェット間の連携がとてもスムーズに行えるようになります。

ユーザー入力イベントの管理

キーボード操作とフォーカス制御

QSpinBoxは、キーボード操作にも柔軟に対応しているため、ユーザーが矢印キーを押すだけで値の増減が行われます。

加えて、キーボード入力による直接編集も受け付け、フォーカスが当たった状態での入力エラーを最小限に抑えてくれる設計となっています。

たとえば、数字だけの入力や、フォーカスが外れた際の自動補正などの機能は、ユーザーが思わず快適に入力できる工夫が施されています。

直接的なイベントハンドリングが必要な場合は、QSpinBoxのイベントフィルタ機能を使い、必要な処理を追加するスタイルも支援されています。

高度なカスタマイズ実装

カスタムQSpinBoxの作成

必要に応じた動作や表示を実現するために、QSpinBoxを継承してカスタムウィジェットとして拡張することが可能です。

C++言語のクラス継承を利用することで、元々の機能に加え独自の処理を実装でき、より柔軟な数値入力ウィジェットを作成できます。

クラス継承による機能拡張

基底クラスであるQSpinBoxの機能に加えて、特定の表示フォーマットや入力ルールを実装することができます。

以下は、簡単な継承例として、基本的なカスタムスピンボックスの実装例です。

#include <QApplication>
#include <QSpinBox>
#include <QWidget>
#include <QDebug>
// CustomSpinBoxクラスはQSpinBoxを継承して、追加の動作を実装する
class CustomSpinBox : public QSpinBox {
public:
    CustomSpinBox(QWidget *parent = nullptr) : QSpinBox(parent) {
        // 初期値や範囲を設定する
        setRange(0, 255);
        setValue(128);
        setMinimumWidth(100);
    }
protected:
    // 入力されたテキストから値を取得するための関数をオーバーライド
    int valueFromText(const QString &text) const override {
        // シンプルな実装例として、通常の整数変換を行う
        return text.toInt();
    }
    // 値を文字列に変換するための関数もオーバーライド
    QString textFromValue(int value) const override {
        // 16進数で表示する例として「0x」プレフィックスを付加する
        return QString("0x%1").arg(value, 0, 16);
    }
};
int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    QWidget window;
    CustomSpinBox customSpinBox(&window);
    customSpinBox.move(20, 20);
    window.show();
    // カスタムスピンボックスの初期化と動作を確認するためのデバッグ出力
    qDebug() << "CustomSpinBox初期値:" << customSpinBox.value();
    return app.exec();
}
// 起動すると、ウィンドウ内に表示されるカスタムスピンボックスには数値が16進数表示で表現される
// 例えば、初期値128は「0x80」と表示される

この例では、CustomSpinBoxクラスがQSpinBoxを継承して、valueFromTexttextFromValueメソッドをオーバーライドし、特殊な表示形式(16進数形式)を実現するための実装を行っています。

textFromValueおよびvalueFromTextのオーバーライド

通常の整数表示以外にも、任意の数値フォーマットを扱いたい場合は、textFromValueおよびvalueFromTextのオーバーライドが有効です。

例えば、数値に特定の単位やフォーマットを追加する場合、これらのメソッドを改良して、ユーザーに直感的な表示を実現できます。

オーバーライドのポイントは、表示部分と内部表現の一致を取ることで、ユーザーが混乱しないように設計することにあります。

特殊な数値フォーマットの実現

16進数表示などのカスタムフォーマット

カスタムQSpinBoxを実装する際、表示する数値を16進数や2進数、あるいは特定のフォーマットで表現したいシーンも考えられます。

例えば、16進数表示を実現する場合、前述のサンプルコードのように、textFromValueメソッドでQString::argを利用して変換処理を入れると、変換後の文字列がウィジェットに反映されます。

以下に、16進数表示の補足サンプルコードとその説明を記載します。

#include <QApplication>
#include <QSpinBox>
#include <QWidget>
#include <QDebug>
class HexSpinBox : public QSpinBox {
public:
    HexSpinBox(QWidget *parent = nullptr) : QSpinBox(parent) {
        // 0〜255の範囲を設定する
        setRange(0, 255);
        setValue(15);
        setMinimumWidth(100);
    }
protected:
    int valueFromText(const QString &text) const override {
        // 入力されたテキストを16進数として解釈する
        bool ok = false;
        int value = text.toInt(&ok, 16);
        return ok ? value : 0;
    }
    QString textFromValue(int value) const override {
        // 数値を16進数文字列に変換する(小文字で表示)
        return QString("0x%1").arg(value, 0, 16);
    }
};
int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    QWidget window;
    HexSpinBox spinBox(&window);
    spinBox.move(20, 20);
    window.show();
    qDebug() << "HexSpinBox初期値:" << spinBox.value();
    return app.exec();
}
// HexSpinBoxが表示され、初期値15は「0xf」として表示される

このコードでは、数値の入力と表示の両面で16進数表現を利用した実装例を示します。

ユーザーは、16進数特有の表現に触れることで、通常の10進数表示とは異なる視点で数値を扱えるようになり、新しい体験を得られるかもしれません。

エラーチェックとデバッグ

入力バリデーションの工夫

validateメソッドの活用と改良

QSpinBoxは、ユーザーが入力した値に対して即座にバリデーションが行われる仕組みを備えています。

入力値があらかじめ決められた範囲外の場合にエラー表示を行ったり、入力途中で修正を促すなど、さまざまな工夫が可能です。

たとえば、validateメソッドをオーバーライドして、ユーザーが入力中の文字列をリアルタイムにチェックし、正確な数値入力を促す実装が考えられます。

以下は、入力バリデーションをシンプルに拡張する例です。

#include <QApplication>
#include <QSpinBox>
#include <QWidget>
#include <QDebug>
#include <QValidator>
class ValidatedSpinBox : public QSpinBox {
public:
    ValidatedSpinBox(QWidget *parent = nullptr) : QSpinBox(parent) {
        setRange(10, 90);
        setValue(50);
        setMinimumWidth(100);
    }
protected:
    QValidator::State validate(QString &input, int &pos) const override {
        // 入力された文字列が数字のみで構成されているかを判定する
        if (input.isEmpty())
            return QValidator::Intermediate;
        bool ok = false;
        int value = input.toInt(&ok);
        // 範囲チェックも行う
        if (!ok || value < 10 || value > 90)
            return QValidator::Invalid;
        return QValidator::Acceptable;
    }
};
int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    QWidget window;
    ValidatedSpinBox spinBox(&window);
    spinBox.move(20, 20);
    window.show();
    qDebug() << "ValidatedSpinBox初期値:" << spinBox.value();
    return app.exec();
}
// ValidatedSpinBoxは、10〜90の範囲内でのみ有効な入力とし、範囲外の入力はエラー扱いとなります

このサンプルコードは、ユーザーが入力中に実施されるバリデーション処理をシンプルに実装しており、特に数値の上下限を保つためのチェックとして有用です。

一般的なトラブルシューティングのポイント

不正入力への対策と例外処理の実装

ユーザーがウィジェットに不正な値を入力した場合、QSpinBoxは内部で自動的に補正を試みるが、プログラム側でも例外処理などを組み込むと安心です。

不正入力への対策として、以下の点に注意するとよいでしょう。

  • 入力範囲とステップ幅の設定が適切か確認する
  • validateメソッドを拡張して、エラー時のフォールバック処理を実装する
  • シグナルを利用して、エラー発生時にユーザーにフィードバックを行う

また、デバッグ時にはqDebugを利用してウィジェットの状態をログ出力する手法が有用です。

コード内にコメントを残しておくことで、トラブルシューティング時に原因をすばやく把握できるように工夫するとよいでしょう。

まとめ

今回の記事では、QSpinBoxの基本的な操作からプロパティ設定、シグナル利用、さらには高度なカスタマイズや入力バリデーション、エラーチェックの実装方法について説明を行った。

ユーザーが直感的に数値入力を扱えるウィジェットとして、QSpinBoxは柔軟に活用できるツールとなります。

シンプルな設定変更でありながら多くの機能が含まれており、実際にプログラムに組み込んでいただければ、操作性やユーザー体験の向上に貢献すること間違いなし。

関連記事

Back to top button