DoubleValidator没有正确检查范围

By simon at 2018-02-28 • 0人收藏 • 64人看过

让我用一个例子来解释这个问题。 如果我们有这样的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.9,399.9或-555.5.至于 你可以看到,这些值不在-359.9和359.9之间。 在[documentation](http://doc.qt.io/qt-5/qml-qtquick- doublevalidator.html#details)我们可以找到以下信息:

输入是accepted但无效,如果它包含一个超出 范围或格式错误;例如在t之后数字太多他小数 点或是空的。 我认为DoubleValidator不接受这种事情,但不幸的是 它确实如此。 所以我想解决方案将是检查最终输入,但我们又一次 一个问题:editingFinished只有在验证器返回时才会发出瓮 可以接受的状态,但情况并非总是如此。 也许我不是在做一个好的方法,我不理解我们如何Ë DoubleValidator或者我可能需要一些C ++代码。 顺便说一下,我正在使用Qt 5.4。

4 个回复 | 最后更新于 2018-02-28
2018-02-28   #1

问题在于[QML TextField](http://doc.qt.io/qt-5/qml- qtquick-controls-textfield.html#validator-prop)accepts intermediate input:

验证器:验证器

允许您在TextField上设置验证器。当验证者是s时et,the TextField 将仅接受将文本属性留在一个中的输入 中间状态*。接受的信号wi只有在文本被发送时才会被发送 按下输入时的可接受状态。 [validate()的功能 QDoubleValidator](HTTp://doc.qt.io/qt-5/qvalidator.html#validate)描述 当它返回QValidator::Intermediate时: *状态QValidator :: validate(QString&iinput,int&pos)const **

如果输入无效,则此虚函数返回无效 验证规则,中如果它可能多一点编辑,那就是中间性的 将使得输入可接受(例如,用户将“4”键入到小部件中)H 接受10到99之间的整数),如果输入有效则接受。 这意味着验证器返回QValidator::Intermediate,只要有双重价值 被输入,并且因为TextField与“中间”可以,你可以输入 任何事物,只要它是一个数字。 你可以做的是继承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("-")) {
            // allow empty field or 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;
    }

};

2018-02-28   #2

问题在于[QML TextField](http://doc.qt.io/qt-5/qml- qtquick-controls-textfield.html#validator-prop)accepts intermediate input:

验证器:验证器

允许您在TextField上设置验证器。当验证者是s时et,the TextField 将仅接受将文本属性留在一个中的输入 中间状态*。接受的信号wi只有在文本被发送时才会被发送 按下输入时的可接受状态。 [validate()的功能 QDoubleValidator](HTTp://doc.qt.io/qt-5/qvalidator.html#validate)描述 当它返回QValidator::Intermediate时: *状态QValidator :: validate(QString&iinput,int&pos)const **

如果输入无效,则此虚函数返回无效 验证规则,中如果它可能多一点编辑,那就是中间性的 将使得输入可接受(例如,用户将“4”键入到小部件中)H 接受10到99之间的整数),如果输入有效则接受。 这意味着验证器返回QValidator::Intermediate,只要有双重价值 被输入,并且因为TextField与“中间”可以,你可以输入 任何事物,只要它是一个数字。 你可以做的是继承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("-")) {
            // allow empty field or 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;
    }

};

2018-02-28   #3

@xsquared提供的答案非常完美。我认为这是个好主意 与任何人分享好奇如何整合解决方案n与QML。 TextFieldDoubleValidator是@xsquared建议的类。 所以首先是在我们的网站注册新的类型主要。 * *的main.cpp

#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();
}
之后,我们可以在我们的QML0应用程序中使用新型号: * * main.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
        }
    }
}

2018-02-28   #4

这是一个纯粹的qml版本:

TextFieldInput{
validator: DoubleValidator
{
    bottom: minimumValue
    top: maximumValue
}

property real maximumValue: constants._MAXIMUM_INTEGER
property real minimumValue: constants._MINIMUM_INTEGER
property string previousText: ""

onTextChanged:
{
    var numericValue = getValue()
    if (numericValue > maximumValue || numericValue < minimumValue)
    {
        text = previousText
    }
    previousText = text
}

function setValue(_value)
{
    text = String(_value)
}

function getValue()
{
    return Number(text)
}}

登录后方可回帖

Loading...