DoubleValidator is not checking the ranges properly

qml validator
qdoublevalidator
qvalidator

Let me use an example to explain the issue.

If we have a TextField like this,

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

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

We can type numbers such as 444.9, 399.9 or -555.5. As you can see, the values are not between -359.9 and 359.9.

In the documentation we can find the following information:

Input is accepted but invalid if it contains a double that is outside the range or is in the wrong format; e.g. with too many digits after the decimal point or is empty.

I thought DoubleValidator didn't accept this kind of things, but unfortunately it does.

So I suppose the solution would be to check the final input, but again we have a problem: editingFinished is only emitted if the validator returns an acceptable state and this is not always the case.

Perhaps I'm not doing a good approach, I'm not understanding how to use DoubleValidator or maybe I need some code in C++.

By the way, I'm working with Qt 5.4.

The problem lies in the fact that QML TextField accepts intermediate input:

validator : Validator

Allows you to set a validator on the TextField. When a validator is set, the TextField will only accept input which leaves the text property in an intermediate state. The accepted signal will only be sent if the text is in an acceptable state when enter is pressed.

The validate()-function of QDoubleValidator describes when it returns QValidator::Intermediate:

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

This virtual function returns Invalid if input is invalid according to this validator's rules, Intermediate if it is likely that a little more editing will make the input acceptable (e.g. the user types "4" into a widget which accepts integers between 10 and 99), and Acceptable if the input is valid.

So that means, the validator returns QValidator::Intermediate, as long as a double value is entered and because TextField is okay with "intermediate", you can type anything as long as it is a number.

What you can do is to subclass QDoubleValidator and to override validate(), so that it does not return Intermediate when the values are out of bounds:

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

};

DoubleValidator - Apache Commons, under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except li> 045 * <li><code>maxValue()</code> checks whether the value is less 046 * than or equal checks whether the value is within 048 * a specified range of values. 073 * @return A singleton instance of the DoubleValidator. If notation is set to DoubleValidator.StandardNotation, and the input contains more digits before the decimal point than a double in the valid range may have, it is also rejected. If notation is DoubleValidator.ScientificNotation, and the input is not in the valid range, it is accecpted but invalid. The value may yet become valid by changing the exponent.

The answer provided by @xsquared was perfect. I think it's a good idea to share with anyone curious how to integrate the solution with QML.

TextFieldDoubleValidator is the class which @xsquared suggested.

So the first thing is to register the new type in our 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();
}

After that, we can use the new type in our QML application:

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

DoubleValidator (Apache Commons Validator 1.6 API), isInRange() checks whether the value is within a specified range of values. So that the same mechanism used for parsing an input value for validation can be used  Check your ANDROID_SDK_ROOT Docker : What is properly the way to config SERVER_NAME and proxy c++ DoubleValidator is not checking the ranges properly By:

Here is a pure qml version:

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

DoubleValidator QML Type, ScientificNotation, and the input is not in the valid range, it is accecpted but invalid. The value may yet become valid by changing the exponent. Property  2 DoubleValidator is not checking the ranges properly Feb 27 '18. 2 create mx dataGrid itemRenderer from spark at runtime Oct 23 '12. 0 Do regex attributes (g, i, m

I found an easier way.

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

When text in TextField is invalid, acceptableInput would change to false, so when text changed ,check the property, if it's false, then call undo() to undo the changes.

QDoubleValidator Class, The QDoubleValidator class provides range checking of floating-point numbers. For example, since QLocale::RejectGroupSeparator is not set by default, the  DoubleValidator is only used once in Config.java and in that instance: public static final Object TOPOLOGY_STATS_SAMPLE_RATE_SCHEMA = ConfigValidation.DoubleValidator; can just be set to: public static final Object TOPOLOGY_STATS_SAMPLE_RATE_SCHEMA = NUMBER.class; Then we can just get rid of the misleading function ConfigValidation.DoubleValidator since it doesn't really check if a object is of double type thus the validator function doesn't really do anything and the name is misleading.

Special Topics: Core Validators | The Definitive Guide to Yii 2.0, Client validation is not enabled as this will only work on the server-side because the date validator currently does not provide This validator checks if the input value is a date, time or datetime in a proper format. ranges : array of IPv4 or IPv6 ranges that are allowed or forbidden. It is equivalent to the double validator. 7 DoubleValidator is not checking the ranges properly Feb 5 '16. 6 Non-localized version of MinGW? Feb 13 '12. 4 'this' of type “Class* const” even though method

Questions for tag qt5.4, DoubleValidator is not checking the ranges properly TextField { text: "0.0" validator: DoubleValidator { bottom: -359.9; top: 359.9; decimals: 1;  The temperature control thermostat monitors the temperature inside the oven and cycles on the heat when the oven temperature gets too low. If the temperature control thermostat is not calibrated Solution 5: The oven sensor works in conjunction with the oven control board to regulate the temperature.

Tutorial core validators, DoubleValidator is not checking the ranges properly. Let me use an example to explain the issue. If we have a TextField like this, TextField { text: "0.0" validator: On electric ranges, one of the heating elements may have malfunctioned. Check to make sure they glow or heat during the cycle. Check the bake element. Turn your range OFF and either remove the fuses or turn the breaker OFF.

Comments
  • The double validator prevents invalid values to be accepted when enter is pressed. Is that not what you want?
  • @xsquared Actually, if I type 500 the TextField shows that value and if I press enter or change to another TextField in the window, the data is not cleared. Do you have a little example to test what you said?
  • I checked the documentation again and indeed found the problem. Please read my answer below, I hope that it helps you.
  • Very good answer! However I ran into a few problems problems which I'd like to share. MyValidator should be TextFieldDoubleValidator and return QValidator::Invalid; is outside the function validate. I need to integrate this new component into my QML application but I had some compilation errors. To solve them, I had to add a new constructor TextFieldDoubleValidator (QObject * parent = 0) : QDoubleValidator(parent) {}. Please, give me your opinion on all this.
  • Ah thank you I integrated your corrections, they are all valid.
  • Great! Thanks to you :)
  • Any idea why out-of-bounds input is a valid as an intermediate state for DoubleValidator but not for IntValidator?
  • The documentation says otherwise. What exactly is your out-of-bounds value and what’s your range?
  • Please correct me if I'm wrong, but I think there are 2 mistakes in above code. 1) TextFieldInput is not a valid QML component. 2) You never used the setValue() function. BTW when I changed these 2 things the code worked like a charm. Thanks a ton for that!! :)