3

I am trying to extend the QSpinBox to be able to enter "NaN" or "nan" as a valid value. According to the documentation i should use the textFromValue, valueFromText, and validate functions to accomplish this but i cant get it to work since its still not allowing me to enter any text besides numbers. Here is what i have in my .h and .cpp files:

CPP file:

#include "CustomIntSpinBox.h"

CustomIntSpinBox::CustomIntSpinBox(QWidget *parent) : QSpinBox(parent)
{
    this->setRange(-32767,32767);
}

QString CustomIntSpinBox::textFromValue(int value) const
{
    if (value == NAN_VALUE)
    {
        return QString::fromStdString("nan");
    }
    else
    {
        return QString::number(value);
    }
}

int CustomIntSpinBox::valueFromText(const QString &text) const
{
    if (text.toLower() == QString::fromStdString("nan"))
    {
        return NAN_VALUE;
    }
    else
    {
        return text.toInt();
    }
}

QValidator::State validate(QString &input, int pos)
{
    return QValidator::Acceptable;
}

H file:

#ifndef CUSTOMINTSPINBOX_H
#define CUSTOMINTSPINBOX_H

#include <QSpinBox>
#include <QWidget>
#include <QtGui>
#include <iostream>

using namespace std;

#define NAN_VALUE 32767

class CustomIntSpinBox : public QSpinBox
{
    Q_OBJECT

public:
    CustomIntSpinBox(QWidget *parent = 0);
    virtual ~CustomIntSpinBox() throw() {}

    int valueFromText(const QString &text) const;
    QString textFromValue(int value) const;
    QValidator::State validate(QString &input, int pos);
};

#endif // CUSTOMINTSPINBOX_H

Is there something im missing? or doing wrong? If theres and easier way to do this also that would be great to know...

MBU
  • 4,998
  • 12
  • 59
  • 98
  • Some suggestions regarding your code, independent of the question: (1) Don't use throw specifications unless you must because the base class does ([Sutter/Alexandrescu](http://www.amazon.com/Coding-Standards-Rules-Guidelines-Practices/dp/0321113586), Item 75). (2) Make your ctor `explicit` (ibid, Item 40). (3) Don't write `using namespace` in a header (ibid., Item 59). (4) Use `static const int NAN_VALUE = 32767;` instead of a `#define` (ibid., Item 16). (5) Don't `#include ` (slows down compilation). (6) Use `QLatin1String("nan")` instead of `QString::fromStdString("nan")` (faster). – Marc Mutz - mmutz Jun 23 '12 at 13:12

3 Answers3

4

The signature of QAbstractSpinBox::validate() is:

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

So your validate() method's signature differs in two ways: its not const, and you have int pos instead of int& pos. Thus it doesn't override QAbstractSpinBox::validate and is never called by QAbstractSpinBox.

Marc Mutz - mmutz
  • 24,485
  • 12
  • 80
  • 90
Frank Osterfeld
  • 24,815
  • 5
  • 58
  • 70
  • Thank your very much! that was the problem. – MBU Apr 13 '12 at 20:27
  • if i wanted to do the same thing for QDoubleSpinBox, will this code still work? or will I have to change the functions to account for the decimal point in the text? – MBU Apr 14 '12 at 00:12
3

If you can extend the lower bound of your range by -1 and use a normal QSpinBox or QDoubleSpinBox and call spinbox->specialValueText("nan"), which will show the string nan when value() == minimum(). The user won't be able to enter the string "nan" manually, but you can always accompany the spinbox with a button that executes spinbox->setValue(spinbox->minimum()). Here's a compilable example:

// main.cpp
#include <QSpinBox>
#include <QDoubleSpinBox>
#include <QDialog>
#include <QApplication>
#include <QVBoxLayout>

#include <limits>

class Tester : public QDialog {
    Q_OBJECT
public:
    static const int NanValue = -32767-1;
    explicit Tester(QWidget * parent=0)
        : QDialog(parent),
          m_spinBox(new QSpinBox(this)),
          m_doubleSpinBox(new QDoubleSpinBox(this))
    {
        QVBoxLayout * vlay = new QVBoxLayout(this);
        vlay->addWidget(m_spinBox);
        vlay->addWidget(m_doubleSpinBox);

        m_spinBox->setRange(NanValue,32767);
        m_doubleSpinBox->setRange(NanValue,32767);

        m_spinBox->setValue(NanValue);
        m_doubleSpinBox->setValue(NanValue);

        updateSpecialValueText();
    }

protected:
    void changeEvent(QEvent *e) {
        QDialog::changeEvent(e);
        if (e->type() == QEvent::LocaleChange)
            updateSpecialValueText();
    }


private:
    void updateSpecialValueText() {
        static const double NaN = std::numeric_limits<double>::quiet_NaN();
        m_spinBox->setSpecialValueText(locale().toString(NaN));
        m_doubleSpinBox->setSpecialValueText(locale().toString(NaN));
    }

private:
    QSpinBox * m_spinBox;
    QDoubleSpinBox * m_doubleSpinBox;
};

int main(int argc, char * argv[]) {
    QApplication app(argc, argv);

    Tester t;
    return t.exec();
}

#include "main.moc"
Marc Mutz - mmutz
  • 24,485
  • 12
  • 80
  • 90
1

Maybe QSpinBox sets a lineEdit wich has a QIntValidator as QValidator. At least the docs of QAbstractSpinBox::setLineEdit suggest that the validator of the lineEdit has priority over the QAbstractSpinBox::validate function.

bjhend
  • 1,538
  • 11
  • 25