C++ 仅允许QLineEdit中的条目在QDoubleValidator的范围内

C++ 仅允许QLineEdit中的条目在QDoubleValidator的范围内,c++,qt,validation,qlineedit,C++,Qt,Validation,Qlineedit,我有一组QLineEdits,它们应该接受特定范围内的双值(例如-15到15) 在设置每一个时,我都有以下内容: lineEdit->setValidator(new QDoubleValidator(minVal, maxVal, 5, lineEdit)); 理想情况下,行编辑可以只输入范围内的值。当我尝试这个方法时,我注意到只有数字可以按需要输入,但它们仍然可能超出范围 如何动态强制输入适应范围(例如,如果范围为-15到15,用户键入1,然后尝试键入9,它不工作/显示9…但键入1,

我有一组
QLineEdits
,它们应该接受特定范围内的双值(例如-15到15)

在设置每一个时,我都有以下内容:

lineEdit->setValidator(new QDoubleValidator(minVal, maxVal, 5, lineEdit));
理想情况下,行编辑可以只输入范围内的值。当我尝试这个方法时,我注意到只有数字可以按需要输入,但它们仍然可能超出范围

如何动态强制输入适应范围(例如,如果范围为-15到15,用户键入1,然后尝试键入9,它不工作/显示9…但键入1,然后键入2可以工作/显示2。)


我需要在某个地方连接并调用
validate()
函数吗?

这是因为
QDoubleValidator
返回
QValidator::Intermediate
如果值超出边界并且
QLineEdit
接受
QValidator::Intermediate

要实现您想要的行为,您可以创建自己的
QDoubleValidator
子类,如下所示:

class MyValidator : public QDoubleValidator
{
public:
    MyValidator(double bottom, double top, int decimals, QObject * parent) :
        QDoubleValidator(bottom, top, decimals, parent)
    {
    }

    QValidator::State validate(QString &s, int &i) const
    {
        if (s.isEmpty()) {
            return QValidator::Intermediate;
        }

        bool ok;
        double d = s.toDouble(&ok);

        if (ok && d > 0 && d < 15) {
            return QValidator::Acceptable;
        } else {
            return QValidator::Invalid;
        }
    }
};
类MyValidator:公共QDoubleValidator
{
公众:
MyValidator(双底、双顶、整数小数、QObject*父项):
QDoubleValidator(底部、顶部、小数、父级)
{
}
QValidator::状态验证(QString&s、int&i)常量
{
如果(s.isEmpty()){
返回QValidator::Intermediate;
}
布尔ok;
双d=s.toDouble(&ok);
如果(ok&&d>0&&d<15){
返回QValidator::可接受;
}否则{
返回QValidator::无效;
}
}
};

更新:这将解决负号问题,还将接受区域设置双格式:

class MyValidator : public QDoubleValidator
{
public:
    MyValidator(double bottom, double top, int decimals, QObject * parent) :
        QDoubleValidator(bottom, top, decimals, parent)
    {
    }

    QValidator::State validate(QString &s, int &i) const
    {
        if (s.isEmpty() || s == "-") {
            return QValidator::Intermediate;
        }

        QChar decimalPoint = locale().decimalPoint();

        if(s.indexOf(decimalPoint) != -1) {
            int charsAfterPoint = s.length() - s.indexOf(decimalPoint) - 1;

            if (charsAfterPoint > decimals()) {
                return QValidator::Invalid;
            }
        }

        bool ok;
        double d = locale().toDouble(s, &ok);

        if (ok && d >= bottom() && d <= top()) {
            return QValidator::Acceptable;
        } else {
            return QValidator::Invalid;
        }
    }
};
类MyValidator:公共QDoubleValidator
{
公众:
MyValidator(双底、双顶、整数小数、QObject*父项):
QDoubleValidator(底部、顶部、小数、父级)
{
}
QValidator::状态验证(QString&s、int&i)常量
{
如果(s.isEmpty()| | s==“-”){
返回QValidator::Intermediate;
}
QChar decimalPoint=locale().decimalPoint();
如果(s.indexOf(小数点)!=-1){
int charsAfterPoint=s.length()-s.indexOf(decimalPoint)-1;
if(charsAfterPoint>decimals()){
返回QValidator::无效;
}
}
布尔ok;
双d=locale().toDouble(s,&ok);

如果(ok&&d>=bottom()&&d我尝试了上面的优秀类,但它仍然需要进行一些编辑。小数点搜索正在缩小“top”指定的范围,因为它在没有小数点时返回“-1”。我添加了一个条件语句来解决这个问题

此外,如果用户试图删除小数点,并且结果值大于范围,则仍需要对其进行调整。现在它只是禁止该行为,而不是将其更改为最大值,这对我来说更直观

class MyValidator : public QDoubleValidator
{
    public:
    MyValidator(double bottom, double top, int decimals, QObject * parent) :
    QDoubleValidator(bottom, top, decimals, parent)
    {
    }

    QValidator::State validate(QString &s, int &i) const
    {
        if (s.isEmpty() || s == "-") {
            return QValidator::Intermediate;
        }

        QLocale locale;

        QChar decimalPoint = locale.decimalPoint();
        int charsAfterPoint = s.length() - s.indexOf(decimalPoint) -1;

        if (charsAfterPoint > decimals() && s.indexOf(decimalPoint) != -1) {
            return QValidator::Invalid;
        }

        bool ok;
        double d = locale.toDouble(s, &ok);

        if (ok && d >= bottom() && d <= top()) {
            return QValidator::Acceptable;
        } else {
            return QValidator::Invalid;
        }
    }
};
类MyValidator:公共QDoubleValidator
{
公众:
MyValidator(双底、双顶、整数小数、QObject*父项):
QDoubleValidator(底部、顶部、小数、父级)
{
}
QValidator::状态验证(QString&s、int&i)常量
{
如果(s.isEmpty()| | s==“-”){
返回QValidator::Intermediate;
}
QLocale语言环境;
QChar decimalPoint=locale.decimalPoint();
int charsAfterPoint=s.length()-s.indexOf(decimalPoint)-1;
if(charsAfterPoint>decimals()&&s.indexOf(decimalPoint)!=-1){
返回QValidator::无效;
}
布尔ok;
双d=locale.toDouble(s,&ok);

如果(ok&&d>=bottom()&&d在检查
QLineEdit
输入的可接受范围时,我花了几乎一天的时间试图让
QDoubleValidator
与合理的用户反馈一起工作。我尝试使用Qt时规定了
validator::fixup()
结果是浪费时间。本帖中的早期答案更有用,但仍有不足之处。最后,我选择了一种不同且更简单的方法

  • QLineEdit
    配备不执行范围检查的
    QDoubleValidator
  • QLineEdit
    编辑的处理程序中,完成
    信号范围检查,必要时重置
    QLineEdit
    文本
  • 这种方法不允许键入非法字符,负责本地化并更正超出所需范围的值


    对我来说效果很好。

    也可以在不使用子类的情况下完成这项工作

    lineEdit = new QLineEdit();
    connect(lineEdit,SIGNAL(textChanged(QString)), this, SLOT(textChangedSlot(QString)));
    
    QDoubleValidator *dblVal = new QDoubleValidator(minVal, maxVal, 1000, lineEdit);
    dblVal->setNotation(QDoubleValidator::StandardNotation);
    dblVal->setLocale(QLocale::C);
    lineEdit->setValidator(dblVal);
    
    区域设置可能很重要,因为它定义了哪些字符被解释为十进制分隔符。输入字符串的格式定义了应该使用哪些区域设置

    在textChangedSlot中,我们可以通过以下方式验证输入:

    QString str = lineEdit->text();
    int i = 0;
    QDoubleValidator *val = (QDoubleValidator *) lineEdit->validator();
    QValidator::State st = val->validate(str, i);
    
    if (st == QValidator::Acceptable) {
        // Validation OK
    } else {
        // Validation NOK
    }
    
    在这种情况下,QValidator::Intermediate状态也被解释为失败的情况


    如果我们将textChanged-signal连接到textChangedSlot,则每次输入字段更改后都会进行验证。我们还可以连接editingFinished()或returnPressed()-向验证槽发送信号。在这种情况下,只有当用户停止编辑字符串时才进行验证。

    VVV的答案对于原始问题nicole非常有效。这是从负到正的范围

    但是,作为QDoubleValidator的通用解决方案,当范围从正到正时,它有一个副作用:

    示例:范围:[87.5…1000.0],输入:“15”(作为中间值达到150)

    当QLineEdit低于下限(或开始为空)时,输入将被拒绝。因此,我扩展了VVV的解决方案作为一般解决方案:

    /*
     * Empty string and the negative sign are intermediate
     */
    if( input.isEmpty() || input == "-" )
    {
        return QValidator::Intermediate;
    }
    /*
     * Check numbers of decimals after the decimal point
     * and the number of decimal points
     */
    QChar decimalPoint = locale().decimalPoint();
    if( input.count( decimalPoint, Qt::CaseInsensitive ) > 1 )
    {
        return QValidator::Invalid;
    }
    else if( input.indexOf( decimalPoint ) != -1)
    {
        const int charsAfterPoint = input.length() - input.indexOf( decimalPoint) - 1;
        if( charsAfterPoint > decimals() )
        {
            return QValidator::Invalid;
        }
    }
    /*
     * Check for valid double conversion and range
     */
    bool ok;
    const double d = locale().toDouble( input, &ok );
    if( ok && d <= top() )
    {
        if( d >= bottom() )
        {
            return QValidator::Acceptable;
        }
        else
        {
            return QValidator::Intermediate;
        }
    }
    else
    {
        return QValidator::Invalid;
    }
    
    /*
    *空字符串和负号是中间的
    */
    if(input.isEmpty()||
    
    #include <QDoubleValidator>
    
    class TruncationValidator : public QDoubleValidator
    {
        Q_OBJECT
    public:
        explicit TruncationValidator(QObject *parent = 0) : QDoubleValidator(parent) {
          connect(this->parent(), SIGNAL(editingFinished()), this, SLOT(truncate()));
        }
        TruncationValidator(double bottom, double top, int decimals, QObject * parent) : QDoubleValidator(bottom, top, decimals, parent) {
          connect(this->parent(), SIGNAL(editingFinished()), this, SLOT(truncate()));
        }
    
        QValidator::State validate(QString &s, int &i) const {
          QValidator::State state = QDoubleValidator::validate(s,i);
    
          if (s.isEmpty()) {
            return state;
          }
    
          bool ok;
          double d = s.toDouble(&ok);
    
          if (ok) {
            // QDoubleValidator returns QValidator::Intermediate if out of bounds
            return QValidator::Acceptable;
          }
          return state;
        }
    
    private slots:
        void truncate() {
          QLineEdit* le = dynamic_cast<QLineEdit*>(parent());
          if (le) {
            QString s = le->text();
            bool ok;
            double d = s.toDouble(&ok);
            if (ok) {
              if (d > this->top() || d < this->bottom()) {
                d = std::min<double>(d, this->top());
                d = std::max<double>(d, this->bottom());
                le->setText(QString::number(d));
              }
            }
          }
        }
    private:
    };