Qt-子类化SpinBox

概述

工作需要,需要对浮点数据进行验证修复,遂想到使用QDoubleSpinBox,但自带的函数不足以满足我的需求,故自行子类化一个SpinBox

需求

  • 设定默认值和范围,范围基于默认值;
  • 设定梯度,如果超出范围或输入数据与默认数据的差不是梯度的整数倍则修正输入数据。

构思

QAbstractSpinBox提供了4个虚函数,分别是fixup,validate,valueFromTexttextFromValue

  • fixup:当validate返回非QValidator::Acceptable时调用。
  • validate:输入时,将输入内容与当前位置作为入参,返回值有三个;
    • QValidator::Invalid = 0:不合法;
    • QValidator::Intermediate = 1:半合法;
    • QValidator::Acceptable = 2: 合法;
  • valueFromText:从字符串转换为值;
  • textFromValue:从值转换为字符串。

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// FollowStepSpinBox.h
class FollowStepSpinBox final
: public QDoubleSpinBox
{
public:
explicit FollowStepSpinBox(QWidget* parent = nullptr);

~FollowStepSpinBox();

// 设置默认值及范围,范围默认为9999
void SetDefaultValue(double value, double range = 9999);

protected:
void fixup(QString &str) const override;

QValidator::State validate(QString &input, int &pos) const override;

double valueFromText(const QString& text) const override;

QString textFromValue(double val) const override;

private:
double mDefaultValue;
};

// FollowStepSpinBox.cpp
FollowStepSpinBox::FollowStepSpinBox(QWidget *parent)
: QDoubleSpinBox(parent)
, mDefaultValue(0)
{
setFixedSize(160, 40);
}

FollowStepSpinBox::~FollowStepSpinBox()
{
}

void FollowStepSpinBox::SetDefaultValue(double value, double range)
{
setRange(value - fabs(range), value + fabs(range));

mDefaultValue = value;
setValue(value);
}

void FollowStepSpinBox::fixup(QString &str)
{
double value = valueFromText(str);
value = mDefaultValue + round((value - mDefaultValue) / singleStep())*singleStep();

// 超过上限
while(value > maximum())
{
value -= singleStep();
}

// 超过下限
while(value < minmun())
{
value += singleStpe();
}
str = QString::number(value);
}

QValidator::State FollowStepSpinBox::validate(QString &input, int &pos) const
{
static QRegExpValidator *validator = new QRegExpValidator(QRegExp("^[0-9\\.]*$"));
if(validator->validate(input,pos) != QValidator::Acceptable)
{
return QValidator::Invalid;
}

const double value = valueFromText(input);
const double times = fabs(value - mDefaultValue) / singleStep();
if(fabs(times - static_cast<int>(round(times)) < 1e-8)
{
return QValidator::Acceptable;
}
return QValidator::Invalid;
}

double FollowStepSpinBox::valueFromText(const QString &text) const
{
return text.toDouble();
}

QString FollowStepSpinBox::textFromValue(double val) const
{
return QString::number(val);
}