Разрешить вход в QLineEdit только в пределах диапазона QDoubleValidator
у меня есть набор QLineEdits
, которые должны принимать двойные значения в определенном диапазоне (например, от -15 до 15).
у меня есть что-то в этом роде при настройке каждого:
lineEdit->setValidator(new QDoubleValidator(minVal, maxVal, 5, lineEdit));
В идеале редактирование строк будет работать так, чтобы можно было вводить только значения в диапазоне. Когда я попробовал это сделать, то заметил, что при желании можно набирать только цифры, но они все еще могут выходить за пределы диапазона.
как я могу динамически заставить вход вписаться в диапазон (например, если диапазон от -15 до 15 и пользователь вводит 1, а затем пытается ввести 9, он не работает/отображает 9...но ввод 1, а затем 2 работает/отображает 2.) ?
мне нужно подключиться и вызвать
6 ответов
потому что QDoubleValidator
возвращает QValidator::Intermediate
если значение находится за пределами границ и QLineEdit
принимает 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::Intermediate состояние интерпретируется как неудачный случай.
если мы подключим textChanged - сигнал в textChangedSlot, проверка выполняется после каждого изменения поля ввода. Мы также можем подключить editingFinished () или 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;
}
}
};
Я потратил почти день, пытаясь сделать QDoubleValidator
работа с разумной обратной связью потребителя проверяя для приемлемого ряда QLineEdit
вход. Мои попытки использовать Qt прописал validator::fixup()
оказалось пустой тратой времени. Более ранние ответы в этой теме гораздо более полезны, но все же имеют недостатки. В конце концов я выбрал другой, более простой подход.
- оборудовать
QLineEdit
СQDoubleValidator
который не выполняет проверку диапазона. - в обработчик
QLineEdit
editingFinished
сигнал делает проверку ряда и при необходимости возвратQLineEdit
текст.
этот подход запрещает ввод незаконных символов, заботится о локализации и корректирует значения за пределами желаемого диапазона.
хорошо работает для меня.
ответ ВВВ отлично подходит для оригинального вопроса Николь. Это когда диапазон от отрицательного к положительному.
однако в качестве общего решения для QDoubleValidator он имеет один побочный эффект, когда диапазон от положительного до положительного:
пример:
я столкнулся с этим решением при поиске решения, которое поддерживает научную, а также стандартную нотацию. Он вдохновлен предложением Петри Pyöriä, вот решение, которое использует сигнал editingFinished
.
я перегружен validate
обеспечить QValidator::Acceptable
возвращается, даже если значение находится вне диапазона. Это вызывает editingFinished
, который я использую для усечения выходных. Таким образом, как научные, так и стандартные обозначения могут использоваться точно так же, как реализованы by 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:
};