QSpinBox子类化一例(进制可变的SpinBox)

目的:创建一个进制可设置的spinbox。

类定义

子类化 QSpinBox 的关键就是实现下面的四个虚函数:

  • fixup()
  • validate()
  • textFromValue()
  • valueFromText()

除此之外,我们要设置采用的进制,所以添加一对函数

  • base()
  • setBase()

创建一个 private 的对象,存放私有变量

最终定义如下:

#ifndef HBASESPINBOX_H #define HBASESPINBOX_H #include <QtGui/QSpinBox> class HBaseSpinBoxPrivate; class HBaseSpinBox : public QSpinBox { Q_OBJECT public: HBaseSpinBox(QWidget *parent = 0); ~HBaseSpinBox(); virtual void fixup(QString& input) const; virtual QValidator::State validate(QString& input, int& pos) const; int base() const; void setBase(int b); protected: virtual QString textFromValue(int value) const; virtual int valueFromText(const QString& text) const; private: HBaseSpinBoxPrivate * d; }; #endif // HBASESPINBOX_H

类的实现文件

  • 先看一下 HBaseSpinBoxPrivate 的实现
    • 一个成员变量,存放当前采用的进制
    • 一个成员函数,用来校验和解析输入的字符串

#include <QtCore/QDebug> #include <QtCore/QStringBuilder> #include <QtGui/QLineEdit> #include "hbasespinbox.h" class HBaseSpinBoxPrivate { public: HBaseSpinBoxPrivate(HBaseSpinBox *spinbox); int validateAndInterpret(QString &input, int &pos, QValidator::State &state); int base; HBaseSpinBox * p; }; HBaseSpinBoxPrivate::HBaseSpinBoxPrivate(HBaseSpinBox *spinbox) :base(10), p(spinbox) {} int HBaseSpinBoxPrivate::validateAndInterpret(QString &input, int &pos, QValidator::State &state) { QString copy = input; if (!p->prefix().isEmpty()) copy = copy.mid(p->prefix().size()); if (!p->suffix().isEmpty()) copy.chop(p->suffix().size()); const int max = p->maximum(); const int min = p->minimum(); state = QValidator::Acceptable; int num = min; if (!copy.size()) { //允许空输入 state = QValidator::Intermediate; } else if (min<0 && copy[0]=='-'){ state = QValidator::Intermediate; } else { bool ok = false; num = copy.toInt(&ok, base); if (!ok) { //转换失败,不可接受 state = QValidator::Invalid; } else if (num >= min && num <= max) { //正常值 state = copy == copy.toUpper()? QValidator::Acceptable : QValidator::Intermediate; } else if ((num >=0 && num > max) || (num < 0 && num < min)) { //数值越界且不可通过后续输入校正 state = QValidator::Invalid; } else { state = QValidator::Intermediate; } } return num; }

类的实现就比较简单了:

HBaseSpinBox::HBaseSpinBox(QWidget *parent) : QSpinBox(parent),d(new HBaseSpinBoxPrivate(this)) { } HBaseSpinBox::~HBaseSpinBox() { delete d; } void HBaseSpinBox::fixup(QString &input) const { QString copy = input; int pos = lineEdit()->cursorPosition(); QValidator::State state; int num = d->validateAndInterpret(copy, pos, state); input = prefix() % QString::number(num, d->base).toUpper() % suffix(); qDebug()<<input; } QValidator::State HBaseSpinBox::validate(QString& input, int& pos) const { QValidator::State state; d->validateAndInterpret(input, pos, state); return state; } int HBaseSpinBox::base() const { return d->base; } void HBaseSpinBox::setBase(int b) { if (b<2 || b>36) qWarning("base must between 2 and 36"); d->base = qBound(2, b, 36); } QString HBaseSpinBox::textFromValue(int value) const { //不包括前缀和后缀 return QString::number(value, d->base).toUpper(); } int HBaseSpinBox::valueFromText(const QString& text) const { QString copy = text; int pos = lineEdit()->cursorPosition(); QValidator::State state; return d->validateAndInterpret(copy, pos, state); }

难点?

  • validate() 函数负责判断用户输入是否有效。
    • 如果数据完全符合条件,就是 QValidator::Acceptable
    • 如果数据肯定不可接受,就是 QValidator::Invalid
    • 如果数据是指部分符合,则返回 QValidator::Intermediate
      • 比如范围是 100~200,当前只输入了 10
      • 比如用户输入 00100,数值正确,但格式不好
      • 比如用户输入 +110,需要处理掉正号
  • fiixup() 最后的修正
    • 对于QValidator::Invalid 和 QValidator::Intermediate 的数据,可以在此进行一次修正。
  • 前缀和后缀的处理,需要搞清楚 validate和fixup中操作的都是包含前后缀的字符串。

你可能感兴趣的:(delete,input)