DoubleValidator 未正确检查范围

问题描述 投票:0回答:5

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

如果我们有这样的

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
之间。

文档中我们可以找到以下信息:

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

我以为

DoubleValidator
不接受这种事情,但不幸的是它接受了。

所以我认为解决方案是检查最终输入,但我们又遇到了一个问题:仅当验证器返回可接受的状态时才会发出

editingFinished
,但情况并非总是如此。

也许我没有采取好的方法,我不明白如何使用

DoubleValidator
或者也许我需要一些C++代码。

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

c++ qt qml qt5.4
5个回答
11
投票

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

验证者:验证者

允许您在文本字段上设置验证器。设置验证器后,TextField 接受输入,这会使文本属性处于中间状态。仅当按下 Enter 键时文本处于可接受的状态时,才会发送已接受的信号。

QDoubleValidator

validate()函数描述了它何时返回
QValidator::Intermediate

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

如果根据此验证器的规则,输入无效,则此虚拟函数返回 Invalid。 如果进行更多编辑可能会使输入可接受(例如,用户在接受 10 到 99 之间的整数的小部件中键入“4”),则返回中间值),如果输入有效则可接受。

这意味着,只要输入双精度值,验证器就会返回

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("-") && 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;
    }

};

4
投票

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

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

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


3
投票

@xsquared 提供的答案非常完美。我认为与任何好奇如何将解决方案与

QML
集成的人分享是个好主意。

TextFieldDoubleValidator
是@xsquared建议的类。

所以第一件事就是在我们的 main 中注册新类型。

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();
}

之后,我们可以在我们的

QML
应用程序中使用新类型:

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
        }
    }
}

3
投票

这是一个纯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)
}}

0
投票

要拒绝输入,必须在 TextField 中使用 RegularExpressionValidator 这只会接受 -359.9 到 359.9

    TextField {
    width: 200
    height: 40
    anchors.centerIn: parent

    validator: RegularExpressionValidator {
        regularExpression: /(-?3[0-5][0-9]?|[1-2]?[0-9][0-9])([.]\d{1})?/
        }
    }
© www.soinside.com 2019 - 2024. All rights reserved.