QLineEdit浮点数输入限制QDoubleValidator

   我的qt版本是qt4.8.4

    QLineEdit *edit1 = new QLineEdit();

    int nPrecision = 2;

    QDoubleValidator *validator = new QDoubleValidator(-999999999, 999999999, nPrecision, edit1);
    validator->setNotation(QDoubleValidator::StandardNotation);//这个很重要
    validator->setLocale(QLocale::C);//这个也很重要
    edit1->setValidator(validator);

 

https://stackoverflow.com/questions/19571033/allow-entry-in-qlineedit-only-within-range-of-qdoublevalidator里有几个方法,没全试,不是太好

 

Ask Question

Asked 5 years, 11 months ago

Active 1 year, 5 months ago

Viewed 10k times

 

6

 

4

I have a set of QLineEdits that are supposed to accept double values within a certain range, (e.g., -15 to 15).

I have something along these lines when setting up each:

lineEdit->setValidator(new QDoubleValidator(minVal, maxVal, 5, lineEdit));

Ideally, the line edits would work such that only values in range can be entered. When I tried this out, I noticed that only numbers could be typed, as desired, but that they could still go out of range.

How can I dynamically force the input to fit into the range (e.g., if range is -15 to 15 and user types a 1, then attempts to type a 9, it doesn't work/display the 9...but typing 1 and then 2 does work/display the 2.) ?

Do I need to connect and call the validate() function somewhere?

c++ qt validation qlineedit

shareimprove this question

edited May 1 '18 at 12:01

 

AAEM

1,17255 silver badges2020 bronze badges

asked Oct 24 '13 at 16:05

nicole

1,80888 gold badges3232 silver badges6969 bronze badges

add a comment

6 Answers

activeoldestvotes

10

 

That's because QDoubleValidator returns QValidator::Intermediate if the value is outside the bounds and QLineEdit accepts QValidator::Intermediate values.

To implement the behavior you want you can make your own QDoubleValidator subclass like this:

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

UPDATE: This will solve the negative sign issue, and also will accept locale double formats:

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

shareimprove this answer

edited Oct 28 '14 at 11:32

answered Oct 24 '13 at 16:36

 

VVV

43644 silver badges1111 bronze badges

  • I adapted this to save the min and max as members since they vary for my different line edits, and it works like a charm. It does have trouble, however, with allowing a user to enter the initial negative sign for a negative number. I'm thinking that might just be the cost of this solution.. – nicole Oct 24 '13 at 22:36

  • Thank you! I have wasted a day on QDoubleValidator, setNotation(QDoubleValidator::StandardNotation), and QLineEdit input masks. None of it behaved as I expected. It would have been quicker to implement old-school-parse character by character entry. Thank you for a solution that actually works! (I made a few changes to allow "+" in addition to "-", fixed char after decimal count, and made range test inclusive of top and bottom ) – Ed of the Mountain Oct 22 '14 at 14:24 

add a comment

4

 

It is possible to do this also without subclassing.

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

Setting of the locale may be important because it defines which characters are interpreted as a decimal separator. Format of the input string defines which locales should be used.

In the textChangedSlot, we can validate input this way:

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
}

In this case also QValidator::Intermediate state is interpreted as a failed case.

If we connect textChanged -signal to the textChangedSlot, validation is done after every input field change. We could also connect editingFinished() or returnPressed() -signals to the validation slot. In that case, validation is done only when user stops editing the string.

shareimprove this answer

answered Jun 18 '15 at 10:24

 

Petri Pyöriä

17155 bronze badges

add a comment

3

 

I tried the excellent class above and it still needs a couple edits. The decimal point search was reducing the range specified by "top" because it returned a "-1" when there is no decimal point. I added a conditional statement that fixes that.

Also, it still needs to be tweaked for the case where the user tries to delete the decimal point and the resulting value is larger than the range. Right now it just prohibits that behavior rather than changing it to the maximum value which seems more intuitive to me.

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

shareimprove this answer

answered Sep 1 '14 at 23:26

user2896552

3122 bronze badges

add a comment

2

 

I spent almost a day trying to make QDoubleValidator work with reasonable user feedback when checking for acceptable range of QLineEdit input. My attempts to use Qt prescribed validator::fixup() turned out to be a waste of time. Earlier answers in this thread are much more useful but still have shortcomings. In the end I opted for a different and simpler approach.

  1. Equip QLineEdit with QDoubleValidator which performs no range checking.
  2. In a handler for QLineEdit editingFinished signal do range checking and if necessary reset of QLineEdit text.

This approach disallows typing of illegal characters, takes care of localization and corrects values outside of desired range.

Works well for me.

shareimprove this answer

edited May 1 '18 at 13:17

 

AAEM

1,17255 silver badges2020 bronze badges

answered May 2 '15 at 15:31

LRaiz

38922 silver badges1515 bronze badges

add a comment

1

 

The answer of VVV works great for the orignal question of nicole. This is when the range is from negative to positive.

However as a general solution for QDoubleValidator it has one side effect when the range is from positive to positive:

Example: Range: [87.5 ... 1000.0], Input: "15" (as intermediate to reach the value 150)

The input will be declined when the QLineEdit goes under the lower limit (or starts empty). Hence I extended the solution of VVV for a general solution:

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

shareimprove this answer

answered Oct 28 '16 at 11:23

Martin H.

3888 bronze badges

add a comment

0

 

I came across this solution when searching for a solution, which supports scientific as well as standard notation. It is inspired by the suggestion by Petri Pyöriä, here is a solution, which uses the signal editingFinished.

I have overloaded validate to ensure that QValidator::Acceptable is returned even when the value is out of range. This triggers the editingFinished, which I use for truncating the output. In this way, both Scientific and Standard notation can be used exactly as implemented 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:
};

shareimprove this answer

answered May 25 '17 at 22:18

Jens Munk

2,9361515 silver badges28

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

金士顿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值