我们都知道Qt自带的QDoubleValidator有一些问题,比如设置范围为30~100,实际输入的值则是0~999,想要处理这些问题,必须自定义QDoubleValidator实现validate和fixup函数达到我们想要的定制效果,下面看具体的应用。
1.QDoubleValidator的基本使用,这里我们使用QLineEdit来限制输入数据30~1500.
ui->lineEdit->setText("30"); //默认值
doubleValidator = new QDoubleValidator(30, 1500, 2, ui->lineEdit);
doubleValidator->setNotation(QDoubleValidator::StandardNotation); //这个必须设置为标准模式
ui->lineEdit->setValidator(doubleValidator);
运行效果:
第一张图是初始值30, 第二张图输入3,小于最小值范围30,没有处理,第三张图输入9999也接受了。
2.现在我们自定义CustomDoubleValidator继承QDoubleValidator,重写validate和fixup函数
QValidator::State CustomDoubleValidator::validate(QString &s, int &n) const
{
if (s.isEmpty())
{
return QValidator::Intermediate;
}
int dotPos = s.indexOf(".");
if (dotPos > 0)
{
int offset = s.length() - dotPos - 1;
if (s.right(offset).length() > decimals())
{
return QValidator::Invalid;
}
}
bool isOk = false;
double value = s.toDouble(&isOk);
if(!isOk || value > top() || value < bottom())
{
return QValidator::Invalid;
}
return QValidator::Acceptable;
}
//当验证通不过时,通过调用 QValidator::fixedup()是这个函数修复错误。
void CustomDoubleValidator::fixup(QString &input) const
{
//这里要做个判断,低于最小值取最小值,例如0.01转换为0.02,
bool isOk = false;
double value = input.toDouble(&isOk);
if(isOk && (value < bottom()))
input = QString("%1").arg(bottom());
}
使用代码
customDoubleValidator = new CustomDoubleValidator(30, 1500, 2, ui->lineEdit_double);
customDoubleValidator->setNotation(QDoubleValidator::StandardNotation); //这个必须设置为标准模式
ui->lineEdit_double->setValidator(customDoubleValidator);
运行结果:
从上面可以看出,左边原生的可以输入小于30的值,右边输入的不能小于30并且不能大于1500,但这也有一个问题,比如要输入500,这个值不能回退先输入5接着输入00,它把小于30的值都当成无效值了。所以这里还得优化下,让用户可以从第一位数据开始输入。在validate添加如下代码
while(1) //避免下界大于1无法输入的问题
{
if(val < bottom())
val = val * 10;
if(val <= top() && val >= bottom())
return QValidator::Intermediate;
if(val > top())
return QValidator::Invalid;
}
运行效果
从上面可以看出,如果输入小于30,光标离开右边的输入框会自动设为最小值30,最大值也不会超过1500的范围。
这种如果是负数,输入-号是无效的,因此还得优化:
if(input.isEmpty() || input == "-")
{
return QValidator::Intermediate;
}
if(val <= top() && val >= bottom())
return QValidator::Acceptable;
if(bottom() < 0 && val < bottom())
return QValidator::Invalid;
这样就可以输入负数了
当然如果项目中很多个地方用到这个输入框我们可以把这种输入封装起来做成自定义的数据限制QLineEdit。下面是具体代码:
#ifndef CUSTOMDOUBLELINEEDIT_H
#define CUSTOMDOUBLELINEEDIT_H
#include <QLineEdit>
class CustomDoubleValidator;
class CustomDoubleLineEdit : public QLineEdit
{
Q_OBJECT
public:
explicit CustomDoubleLineEdit(QWidget *parent = nullptr);
void setRange(double minimum, double maximum, int decimals = 0);
double minRange();
double maxRange();
int decimals();
private:
void initView();
private:
CustomDoubleValidator *m_doubleValidator;
};
#endif // CUSTOMDOUBLELINEEDIT_H
#include "customdoublelineedit.h"
#include "customdoublevalidator.h"
#include <QDebug>
CustomDoubleLineEdit::CustomDoubleLineEdit(QWidget *parent):
QLineEdit{parent},
m_doubleValidator(new CustomDoubleValidator(this))
{
initView();
}
void CustomDoubleLineEdit::setRange(double minimum, double maximum, int decimals)
{
m_doubleValidator->setRange(minimum, maximum, decimals);
}
double CustomDoubleLineEdit::minRange()
{
return m_doubleValidator->bottom();
}
double CustomDoubleLineEdit::maxRange()
{
return m_doubleValidator->top();
}
int CustomDoubleLineEdit::decimals()
{
return m_doubleValidator->decimals();
}
void CustomDoubleLineEdit::initView()
{
m_doubleValidator->setNotation(QDoubleValidator::StandardNotation);
this->setValidator(m_doubleValidator);
}
使用:
ui->lineEdit_double_custom->setRange(-30, 1500, 2);
lineEdit_double_custom是自定义的CustomDoubleLineEdit
有时候我们在使用的过程中可把会改变setValidator的范围,比如初始值是30~1500,切换单位后就变成了1800~90000,这个时候我们再重新设置范围即可,例如:
void QDoubleValidatorDemo::slotChangeRange()
{
ui->lineEdit->setText("1800");
ui->lineEdit_double->setText("1800");
ui->lineEdit_double_custom->setText("-1800");
doubleValidator->setRange(1800, 90000);
customDoubleValidator->setRange(1800, 90000);
ui->lineEdit_double_custom->setRange(-1800, 90000, 0);
}
运行效果:
发现一个严重的问题,自从切换范围后,设置了默认值,可以输入字母了,看源码好像也没有什么错。百思不得其解,后面把设置默认值的顺序放在设置范围之后就解问心有愧了这个问题。
即:
void QDoubleValidatorDemo::slotChangeRange()
{
doubleValidator->setRange(1800, 90000);
customDoubleValidator->setRange(1800, 90000);
ui->lineEdit_double_custom->setRange(-1800, 90000, 0);
ui->lineEdit->setText("1800");
ui->lineEdit_double->setText("1800");
ui->lineEdit_double_custom->setText("-1800");
}
现在就可以了
完整代码如下:
#ifndef CUSTOMDOUBLEVALIDATOR_H
#define CUSTOMDOUBLEVALIDATOR_H
#include <QDoubleValidator>
class CustomDoubleValidator : public QDoubleValidator
{
Q_OBJECT
public:
explicit CustomDoubleValidator(QObject *parent = nullptr);
CustomDoubleValidator(double bottom, double top, int decimals = 0, QObject *parent = nullptr);
void setRange(double bottom, double top, int decimals = 0) override;
virtual State validate(QString &s, int &n) const override;
virtual void fixup(QString &input) const override;
};
#endif // CUSTOMDOUBLEVALIDATOR_H
#include "customdoublevalidator.h"
#include <QDebug>
CustomDoubleValidator::CustomDoubleValidator(QObject *parent)
: QDoubleValidator{parent}
{
}
CustomDoubleValidator::CustomDoubleValidator(double bottom, double top, int decimals, QObject *parent)
:QDoubleValidator(bottom, top, decimals, parent)
{
setRange(bottom, top, decimals);
}
void CustomDoubleValidator::setRange(double bottom, double top, int decimals)
{
QDoubleValidator::setRange(bottom, top, decimals);
}
//validate()是验证的过程,返回结果是State。每当输入有变化时调用此方法
//enum State {
// Invalid, //验证通不过
// Intermediate, //输入未完成,不确定是否能通过验证
// Acceptable //验证通过
//}
QValidator::State CustomDoubleValidator::validate(QString &input, int &n) const
{
if(input.isEmpty() || input == "-")
{
return QValidator::Intermediate;
}
bool OK = false;
double val = input.toDouble(&OK);
qDebug() << "CustomDoubleValidator::validate====================input===" << input << " n=" << n;
if(!OK)
{
return QValidator::Invalid;
}
int dotPos = input.indexOf(".");
if(dotPos > 0)
{
if(input.right(input.length() - dotPos - 1).length() > decimals())
{
return QValidator::Invalid;
}
}
if(val <= top() && val >= bottom())
return QValidator::Acceptable;
if(bottom() < 0 && val < bottom())
return QValidator::Invalid;
while(1) //避免下界大于1无法输入的问题
{
if(val < bottom())
val = val * 10;
if(val <= top() && val >= bottom())
return QValidator::Intermediate;
if(val > top())
return QValidator::Invalid;
}
return QValidator::Acceptable;
}
//当验证通不过时,通过调用 QValidator::fixedup()是这个函数修复错误。
void CustomDoubleValidator::fixup(QString &input) const
{
//这里要做个判断,低于最小值取最小值,例如0.01转换为0.02,
bool isOk = false;
double value = input.toDouble(&isOk);
if(isOk && (value < bottom()))
input = QString("%1").arg(bottom());
//当输入为'-0'时,修正为0
if("-0" == input)
input = "0";
}
#ifndef QLINEEDITDEMO_H
#define QLINEEDITDEMO_H
#include <QMainWindow>
class QDoubleValidator;
class CustomDoubleValidator;
QT_BEGIN_NAMESPACE
namespace Ui { class QDoubleValidatorDemo; }
QT_END_NAMESPACE
class QDoubleValidatorDemo : public QMainWindow
{
Q_OBJECT
public:
QDoubleValidatorDemo(QWidget *parent = nullptr);
~QDoubleValidatorDemo();
void initView();
void initData();
public slots:
void slotChangeRange();
private:
Ui::QDoubleValidatorDemo *ui;
QDoubleValidator *doubleValidator;
CustomDoubleValidator *customDoubleValidator;
};
#endif // QLINEEDITDEMO_H
#include "qdoublevalidatordemo.h"
#include "ui_qdoublevalidatordemo.h"
#include "customdoublevalidator.h"
QDoubleValidatorDemo::QDoubleValidatorDemo(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::QDoubleValidatorDemo)
{
ui->setupUi(this);
initView();
initData();
}
QDoubleValidatorDemo::~QDoubleValidatorDemo()
{
delete ui;
}
void QDoubleValidatorDemo::initView()
{
QString strLineEditStyle = QString("QLineEdit{background-color:#FFFFFF;color:#333333;border:none;}"
"QLineEdit:hover{color:#333333;border:none;}"
"QLineEdit:focus{color:#333333;border-radius:2px;border:2px solid #2F89FC;}"
"QLineEdit:disabled{background-color:#F0F0F0;border-radius:8px;}");
//灰底
QString strLineEditStyle2 = QString("QLineEdit{background-color:#E9E9EA;color:#6D6E6B;border-radius:5px;}"
"QLineEdit:hover{background-color:#E9E9EA;border-radius:5px;border:2px solid rgba(47, 137, 252, 1);}"
"QLineEdit:focus{background-color:#E9E9EA;border-radius:5px;border:2px solid rgba(47, 137, 252, 1);}"
"QLineEdit:disabled{background-color:#F0F0F0;border-radius:5px;}");
//白底
QString strLineEditStyle3 = QString("QLineEdit{background-color:#FFFFFF;color:#6D6E6B;border-radius:8px;border:2px solid #E8EAEC;}"
"QLineEdit:hover{color:#6D6E6B;border-radius:8px;border:2px solid #2F89FC;}"
"QLineEdit:focus{color:#6D6E6B;border-radius:8px;border:2px solid #2F89FC;}"
"QLineEdit:disabled{background-color:#F0F0F0;border-radius:8px;}");
QFont font = qApp->font();
font.setPixelSize(14);
ui->lineEdit->setStyleSheet(strLineEditStyle);
ui->lineEdit_double->setStyleSheet(strLineEditStyle2);
ui->lineEdit_double_custom->setStyleSheet(strLineEditStyle3);
ui->label->setFont(font);
ui->label_2->setFont(font);
connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(slotChangeRange()));
}
void QDoubleValidatorDemo::initData()
{
ui->lineEdit->setText("30"); //默认值
ui->lineEdit_double->setText("30");
ui->lineEdit_double_custom->setText("-30");
doubleValidator = new QDoubleValidator(30, 1500, 2, ui->lineEdit);
doubleValidator->setNotation(QDoubleValidator::StandardNotation); //这个必须设置为标准模式
ui->lineEdit->setValidator(doubleValidator);
customDoubleValidator = new CustomDoubleValidator(30, 1500, 2, ui->lineEdit_double);
customDoubleValidator->setNotation(QDoubleValidator::StandardNotation); //这个必须设置为标准模式
ui->lineEdit_double->setValidator(customDoubleValidator);
ui->lineEdit_double_custom->setRange(-30, 1500, 2);
}
void QDoubleValidatorDemo::slotChangeRange()
{
//这个一定要放在setText之前,否则在1800后面输入字母没有触发有效验证
doubleValidator->setRange(1800, 90000);
customDoubleValidator->setRange(1800, 90000);
ui->lineEdit_double_custom->setRange(-1800, 90000, 0);
ui->lineEdit->setText("1800");
ui->lineEdit_double->setText("1800");
ui->lineEdit_double_custom->setText("-1800");
}
参考:
https://blog.csdn.net/Joker__123/article/details/125517029
https://blog.csdn.net/u011391361/article/details/132101193
https://blog.csdn.net/iamqianrenzhan/article/details/115931629
https://blog.csdn.net/qq_41965346/article/details/125654944