自定义QDoubleValidator及一些注意事项

我们都知道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

PyQt是一个Python绑定库,用于访问Qt框架,它提供了一种将Qt功能与Python语言集成的方式。QDoubleValidatorQt中的一个类,用于验证用户输入的双精度数字。如果你想要在PyQt中重写这个类,通常是为了自定义验证规则或行为。 `QDoubleValidator`的原始实现允许设置最小值、最大值、步长等限制,并处理小数点、正负符号等常规格式。如果你需要创建自定义版本,可能会这样做: ```python from PyQt5.QtCore import QDoubleValidator, QRect class CustomDoubleValidator(QDoubleValidator): def __init__(self, parent=None): super().__init__(parent) # 添加额外的限制或修改验证逻辑 self.setRange(-10000, 10000) # 示例:只接受-10000到10000之间的数值 self.setDecimals(2) # 设置最多两位小数 self.setTrailingDigitsPolicy(self.TrailingNumbers) def validate(self, input_, pos): value = super().validate(input_, pos) if value == QDoubleValidator.Acceptable: # 进一步检查输入是否符合特定规则 custom_valid = self.check_custom_format(input_) if not custom_valid: return QDoubleValidator.Invalid return value def check_custom_format(self, input_): # 自定义你的验证函数 formatted_input = format(float(input_), '.2f') # 检查格式、特殊字符等 if formatted_input != input_: return False # 如果通过所有检查,返回True return True ``` 在这个例子中,我们重写了`validate()`方法并在`check_custom_format()`里添加了自定义验证条件。然后你可以像使用标准`QDoubleValidator`一样使用`CustomDoubleValidator`。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值