DoubleValidator 没有正确检查范围
DoubleValidator is not checking the ranges properly
让我用一个例子来说明这个问题。
如果我们有这样的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中我们可以找到以下信息:
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.
我以为DoubleValidator
不接受这种东西,但不幸的是它接受了。
所以我想解决方案是检查最终输入,但我们又遇到了一个问题:editingFinished
仅在验证器 returns 处于可接受状态时才会发出,而这并不总是案例.
也许我没有采用好的方法,我不了解如何使用 DoubleValidator
或者我可能需要一些 C++ 代码。
顺便说一下,我正在使用 Qt 5.4。
问题在于QML TextField接受中级输入:
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.
validate()
-function of QDoubleValidator描述的是什么时候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.
所以这意味着,验证器 returns QValidator::Intermediate
,只要输入双精度值,并且因为 TextField 可以使用“中间”,您可以输入任何内容,只要它是一个数字。
你可以做的是继承 QDoubleValidator
并覆盖 validate()
,这样当值超出范围时它不会 return 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;
}
};
@xsquared 提供的答案是完美的。我认为与任何好奇如何将解决方案与 QML
.
集成的人分享是个好主意
TextFieldDoubleValidator
是@xsquared 建议的 class。
所以第一件事就是在我们的 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
}
}
}
这里是纯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)
}}
我找到了更简单的方法。
TextField {
id: control
onTextChanged:
{
if(!acceptableInput)
control.undo()
}
}
当 TextField 中的文本无效时,acceptableInput 将变为 false,因此当文本更改时,检查 属性,如果为 false,则调用 undo() 撤消更改。
让我用一个例子来说明这个问题。
如果我们有这样的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中我们可以找到以下信息:
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.
我以为DoubleValidator
不接受这种东西,但不幸的是它接受了。
所以我想解决方案是检查最终输入,但我们又遇到了一个问题:editingFinished
仅在验证器 returns 处于可接受状态时才会发出,而这并不总是案例.
也许我没有采用好的方法,我不了解如何使用 DoubleValidator
或者我可能需要一些 C++ 代码。
顺便说一下,我正在使用 Qt 5.4。
问题在于QML TextField接受中级输入:
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.
validate()
-function of QDoubleValidator描述的是什么时候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.
所以这意味着,验证器 returns QValidator::Intermediate
,只要输入双精度值,并且因为 TextField 可以使用“中间”,您可以输入任何内容,只要它是一个数字。
你可以做的是继承 QDoubleValidator
并覆盖 validate()
,这样当值超出范围时它不会 return 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;
}
};
@xsquared 提供的答案是完美的。我认为与任何好奇如何将解决方案与 QML
.
TextFieldDoubleValidator
是@xsquared 建议的 class。
所以第一件事就是在我们的 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
}
}
}
这里是纯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)
}}
我找到了更简单的方法。
TextField {
id: control
onTextChanged:
{
if(!acceptableInput)
control.undo()
}
}
当 TextField 中的文本无效时,acceptableInput 将变为 false,因此当文本更改时,检查 属性,如果为 false,则调用 undo() 撤消更改。