只允许在QDoubleValidator的范围内输入QLineEdit
Allow entry in QLineEdit only within range of QDoubleValidator
我有一组QLineEdits
应该接受一定范围内的双精度值(例如,-15 到 15)。
在设置每个时,我有一些类似的东西:
lineEdit->setValidator(new QDoubleValidator(minVal, maxVal, 5, lineEdit));
理想情况下,行编辑将工作,以便只能输入范围内的值。当我尝试这个时,我注意到只能根据需要键入数字,但它们仍然可以超出范围。
我如何动态强制输入适合范围(例如,如果范围是 -15 到 15 并且用户键入 1,然后尝试键入 9,它不起作用/显示 9...但键入 1 然后 2 确实有效/显示 2。
我是否需要在某处连接并调用validate()
函数?
这是因为如果值超出边界并且QLineEdit
接受QValidator::Intermediate
值,则QDoubleValidator
返回QValidator::Intermediate
。
要实现你想要的行为,你可以像这样创建自己的QDoubleValidator
子类:
class MyValidator : public QDoubleValidator
{
public:
MyValidator(double bottom, double top, int decimals, QObject * parent) :
QDoubleValidator(bottom, top, decimals, parent)
{
}
QValidator::State validate(QString &s, int &i) const
{
if (s.isEmpty()) {
return QValidator::Intermediate;
}
bool ok;
double d = s.toDouble(&ok);
if (ok && d > 0 && d < 15) {
return QValidator::Acceptable;
} else {
return QValidator::Invalid;
}
}
};
更新:这将解决负号问题,并且还将接受区域设置双格式:
class MyValidator : public QDoubleValidator
{
public:
MyValidator(double bottom, double top, int decimals, QObject * parent) :
QDoubleValidator(bottom, top, decimals, parent)
{
}
QValidator::State validate(QString &s, int &i) const
{
if (s.isEmpty() || s == "-") {
return QValidator::Intermediate;
}
QChar decimalPoint = locale().decimalPoint();
if(s.indexOf(decimalPoint) != -1) {
int charsAfterPoint = s.length() - s.indexOf(decimalPoint) - 1;
if (charsAfterPoint > decimals()) {
return QValidator::Invalid;
}
}
bool ok;
double d = locale().toDouble(s, &ok);
if (ok && d >= bottom() && d <= top()) {
return QValidator::Acceptable;
} else {
return QValidator::Invalid;
}
}
};
没有子类的情况下做到这一点。
lineEdit = new QLineEdit();
connect(lineEdit,SIGNAL(textChanged(QString)), this, SLOT(textChangedSlot(QString)));
QDoubleValidator *dblVal = new QDoubleValidator(minVal, maxVal, 1000, lineEdit);
dblVal->setNotation(QDoubleValidator::StandardNotation);
dblVal->setLocale(QLocale::C);
lineEdit->setValidator(dblVal);
区域设置可能很重要,因为它定义了将哪些字符解释为小数分隔符。输入字符串的格式定义应使用的区域设置。
在 textChangedSlot 中,我们可以这样验证输入:
QString str = lineEdit->text();
int i = 0;
QDoubleValidator *val = (QDoubleValidator *) lineEdit->validator();
QValidator::State st = val->validate(str, i);
if (st == QValidator::Acceptable) {
// Validation OK
} else {
// Validation NOK
}
在这种情况下,QValidator::中间状态也被解释为失败的情况。
如果我们将 textChanged -signal 连接到 textChangedSlot,则在每个输入字段更改后都会进行验证。我们还可以将 editorDone() 或 returnPressed() 信号连接到验证槽。在这种情况下,仅当用户停止编辑字符串时,才会执行验证。
我尝试了上面的优秀类,它仍然需要一些编辑。 小数点搜索正在缩小"top"指定的范围,因为当没有小数点时,它返回"-1"。 我添加了一个条件语句来解决这个问题。
此外,对于用户尝试删除小数点并且结果值大于范围的情况,它仍然需要进行调整。 现在它只是禁止这种行为,而不是将其更改为对我来说似乎更直观的最大值。
class MyValidator : public QDoubleValidator
{
public:
MyValidator(double bottom, double top, int decimals, QObject * parent) :
QDoubleValidator(bottom, top, decimals, parent)
{
}
QValidator::State validate(QString &s, int &i) const
{
if (s.isEmpty() || s == "-") {
return QValidator::Intermediate;
}
QLocale locale;
QChar decimalPoint = locale.decimalPoint();
int charsAfterPoint = s.length() - s.indexOf(decimalPoint) -1;
if (charsAfterPoint > decimals() && s.indexOf(decimalPoint) != -1) {
return QValidator::Invalid;
}
bool ok;
double d = locale.toDouble(s, &ok);
if (ok && d >= bottom() && d <= top()) {
return QValidator::Acceptable;
} else {
return QValidator::Invalid;
}
}
};
我花了将近一天的时间试图在检查可接受的QLineEdit
输入范围时QDoubleValidator
合理的用户反馈下工作。我尝试使用Qt规定的validator::fixup()
结果证明是浪费时间。此线程中的早期答案更有用,但仍然存在缺点。最后,我选择了一种不同且更简单的方法。
- 为
QLineEdit
配备不执行范围检查的QDoubleValidator
。 - 在用于
QLineEdit
editingFinished
信号的处理程序中,进行范围检查,并在必要时重置QLineEdit
文本。
此方法不允许键入非法字符,负责本地化并更正所需范围之外的值。
对我来说效果很好。
VVV 的答案非常适合妮可的原始问题。这是范围从负到正的时候。
然而,作为QDoubleValidator的一般解决方案,当范围从正到正时,它有一个副作用:
示例:范围:[87.5 ...1000.0],输入:"15"(作为中间值达到值 150)
当 QLineEdit 低于下限(或开始时为空)时,输入将被拒绝。因此,我将VVV的解决方案扩展为通用解决方案:
/*
* Empty string and the negative sign are intermediate
*/
if( input.isEmpty() || input == "-" )
{
return QValidator::Intermediate;
}
/*
* Check numbers of decimals after the decimal point
* and the number of decimal points
*/
QChar decimalPoint = locale().decimalPoint();
if( input.count( decimalPoint, Qt::CaseInsensitive ) > 1 )
{
return QValidator::Invalid;
}
else if( input.indexOf( decimalPoint ) != -1)
{
const int charsAfterPoint = input.length() - input.indexOf( decimalPoint) - 1;
if( charsAfterPoint > decimals() )
{
return QValidator::Invalid;
}
}
/*
* Check for valid double conversion and range
*/
bool ok;
const double d = locale().toDouble( input, &ok );
if( ok && d <= top() )
{
if( d >= bottom() )
{
return QValidator::Acceptable;
}
else
{
return QValidator::Intermediate;
}
}
else
{
return QValidator::Invalid;
}
在寻找支持科学和标准符号的解决方案时,我遇到了这个解决方案。它的灵感来自Petri Pyöriä的建议,这是一个解决方案,它使用信号editingFinished
。
我已经重载了validate
以确保即使值超出范围也返回QValidator::Acceptable
。这会触发editingFinished
,我用它来截断输出。通过这种方式,科学和标准符号都可以完全按照QDoubleValidator
实现的方式使用
#include <QDoubleValidator>
class TruncationValidator : public QDoubleValidator
{
Q_OBJECT
public:
explicit TruncationValidator(QObject *parent = 0) : QDoubleValidator(parent) {
connect(this->parent(), SIGNAL(editingFinished()), this, SLOT(truncate()));
}
TruncationValidator(double bottom, double top, int decimals, QObject * parent) : QDoubleValidator(bottom, top, decimals, parent) {
connect(this->parent(), SIGNAL(editingFinished()), this, SLOT(truncate()));
}
QValidator::State validate(QString &s, int &i) const {
QValidator::State state = QDoubleValidator::validate(s,i);
if (s.isEmpty()) {
return state;
}
bool ok;
double d = s.toDouble(&ok);
if (ok) {
// QDoubleValidator returns QValidator::Intermediate if out of bounds
return QValidator::Acceptable;
}
return state;
}
private slots:
void truncate() {
QLineEdit* le = dynamic_cast<QLineEdit*>(parent());
if (le) {
QString s = le->text();
bool ok;
double d = s.toDouble(&ok);
if (ok) {
if (d > this->top() || d < this->bottom()) {
d = std::min<double>(d, this->top());
d = std::max<double>(d, this->bottom());
le->setText(QString::number(d));
}
}
}
}
private:
};
这是一个解决方法:您可以简单地使用 QDoubleSpinBox
将其buttonSymbols
设置为 NoButtons
,这看起来像一个QLineEdit
,但您可以使用本机 setMinimum(double min)
和 setMaximum(double max)
设置其范围。
此方法在Qt Designer中直接可用。
这是使用PyQt的用户的python版本:
from PyQt5.QtGui import QDoubleValidator, QValidator
class DoubleValidator(QDoubleValidator):
def __init__(self, *__args):
super().__init__(*__args)
def validate(self, p_str, p_int):
if not p_str:
return QValidator.Intermediate, p_str, p_int
if self.bottom() <= float(p_str) <= self.top():
return QValidator.Acceptable, p_str, p_int
else:
return QValidator.Invalid, p_str, p_int
- 为什么在全局范围内使用"extern int a"似乎不行?
- 错误:未在此范围内声明'reverse'
- 并行用于C++17中数组索引范围内的循环
- 求出有多少个数字是完美平方,而sqrt()是L,R范围内的素数
- 不计算一个范围内的完美数
- 错误:"imread"未在此范围内声明
- 我在范围内未声明的错误类有问题
- 如何在cpp中使用地图显示给定日期范围内(在下面的问题中)的费率?
- 我有一个数组,我想输入一个范围,然后找到范围内所有偶数的总和?
- 从用户输入范围内输出质量数量
- 循环直到整数输入在所需范围内无法处理非数字字符输入
- <algorithm>在同一输入迭代器范围内并排运行两个
- 在此范围内未声明"输入"
- 只允许在QDoubleValidator的范围内输入QLineEdit
- 在C++中实现随机预言机(输出在范围内是随机的,但对于相同的输入输出是相同的)
- 检查输入是否在其C++限制范围内
- 输入10^1000范围内的整数
- 检查输入是否为特定类型并在特定范围内
- 检查输入是否在c++中指定的范围内
- 使用 while 循环打印两个用户输入值范围内的数字