DoubleValidator未正确检查范围

时间:2016-02-03 13:34:28

标签: c++ qt qml qt5.4

让我用一个例子来解释这个问题。

如果我们有这样的TextField

TextField {
    text: "0.0"
    validator: DoubleValidator { bottom: -359.9;
        top: 359.9;
        decimals: 1;
        notation: DoubleValidator.StandardNotation }

    onEditingFinished: {
        console.log("I'm here!");
    }                    
}

我们可以输入444.9399.9-555.5等数字。如您所见,这些值不在-359.9359.9之间。

documentation中,我们可以找到以下信息:

  

接受输入但如果包含双精度则无效   超出范围或格式错误;例如数字太多了   小数点后或为空。

我认为DoubleValidator不接受这种事情,但不幸的是它确实如此。

所以我认为解决方案是检查最终输入,但我们又遇到了一个问题:只有在验证器返回可接受状态时才会发出editingFinished,并且情况并非总是这样。

也许我没有做好方法,我不理解如何使用DoubleValidator或者我需要一些C ++代码。

顺便说一句,我正在使用Qt 5.4。

3 个答案:

答案 0 :(得分:4)

问题在于QML TextField接受中间输入:

  

验证者:验证者

     

允许您在TextField上设置验证器。设置验证程序后,TextField 接受输入,使文本属性处于中间状态。只有当按下输入时文本处于可接受状态时,才会发送接受的信号。

validate()-function of QDoubleValidator描述何时返回QValidator::Intermediate

  

状态QValidator :: validate(QString& input,int& pos)const

     

如果根据此验证器的规则输入无效,则此虚函数返回无效中级,如果可能多一点编辑将使输入可接受(例如用户类型" 4& #34;进入一个小部件,接受10到99之间的整数),如果输入有效则可接受。

这意味着,验证器返回QValidator::Intermediate,只要输入一个double值,并且因为TextField可以使用" intermediate",只要它是一个数字就可以输入任何内容。

您可以做的是继承QDoubleValidator并覆盖validate(),以便在值超出范围时它不会返回Intermediate

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

    QValidator::State validate(QString & s, int & pos) const {
        if (s.isEmpty() || (s.startsWith("-") && s.length() == 1)) {
            // allow empty field or standalone minus sign
            return QValidator::Intermediate;
        }
        // check length of decimal places
        QChar point = locale().decimalPoint();
        if(s.indexOf(point) != -1) {
            int lengthDecimals = s.length() - s.indexOf(point) - 1;
            if (lengthDecimals > decimals()) {
                return QValidator::Invalid;
            }
        }
        // check range of value
        bool isNumber;
        double value = locale().toDouble(s, &isNumber);
        if (isNumber && bottom() <= value && value <= top()) {
            return QValidator::Acceptable;
        }
        return QValidator::Invalid;
    }

};

答案 1 :(得分:2)

我找到了一种更简单的方法。

TextField {
    id: control
    onTextChanged:
    {
        if(!acceptableInput)
            control.undo()
    }
}

当TextField中的文本无效时,acceptableInput将更改为false,因此当文本更改时,请检查属性(如果为false),然后调用undo()撤消更改。

答案 2 :(得分:1)

@xsquared提供的答案非常完美。我认为与任何好奇的人如何将解决方案与TextFieldDoubleValidator集成在一起是个好主意。

#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QtQml> #include "textfielddoublevalidator.h" int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); qmlRegisterType<TextFieldDoubleValidator>("TextFieldDoubleValidator", 1,0, "TextFieldDoubleValidator"); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); return app.exec(); } 是@xsquared建议的类。

所以首先要在我们的主要注册新类型。

<强>的main.cpp

QML

之后,我们可以在import QtQuick 2.5 import QtQuick.Window 2.2 import QtQuick.Controls 1.4 import TextFieldDoubleValidator 1.0 Window { visible: true // DoubleValidator doesn't clear the TextField when // text > 359.9 or < -359.9 TextField { text: "0.0" validator: DoubleValidator { bottom: -359.9; top: 359.9; decimals: 1; notation: DoubleValidator.StandardNotation } } // Solution: use your own DoubleValidator. // This works OK and text is cleared out when // text > 359.9 or < -359.9 TextField { y: 50 text: "0.0" validator: TextFieldDoubleValidator { bottom: -359.9; top: 359.9; decimals: 1; notation: DoubleValidator.StandardNotation } } } 应用程序中使用新类型:

<强> main.qml

{{1}}