QLineEdit
has a signal QLineEdit::editingFinished
that gets emitted when the user finished editing, for example by pressing enter. However if a validator or an input mask was set, then editingFinished
only gets emitted if the input is valid.
But how can I react to the user finishing the editing regardless of the validity of the input? Do I have to manually check for enter, return, the widget losing focus, etc. ?
The reason for this: I wanted to create a custom widget for editing numbers using a QDoubleValidator
. When the user finishes editing and the input is invalid (wrong range, empty text, ...) I want to reset it to some valid default value. Something like this:
class NumberEdit: public QLineEdit
{
public:
NumberEdit(double min, double max)
{
setValidator(new QDoubleValidator(min, max, 10));
setText(QString::number(min));
connect(this, /* this is the problem */, [this, min]() {
if(!hasAcceptableInput())
setText(QString::number(min)); // Reset to valid number
});
}
};
I don't think you really need to subclass QLineEdit
.
The clean way to change a QLineEdit
value when it does not have an Acceptable
input, is to override QValidator
and provide an implementation for fixup()
. From the docs:
fixup()
is provided for validators that can repair some user errors. The default implementation does nothing.QLineEdit
, for example, will callfixup()
if the user presses Enter (or Return) and the content is not currently valid. This allows thefixup()
function the opportunity of performing some magic to make anInvalid
stringAcceptable
.
Since you are using QDoubleValidator
, you can subclass it and provide an implementation for fixup()
, as it does not have one, see here.
The class should look something like this:
class MyDoubleValidator : public QDoubleValidator{
public:
explicit MyDoubleValidator(QObject* parent= nullptr)
:QDoubleValidator(parent){}
MyDoubleValidator(double bottom, double top, int decimals, QObject* parent=nullptr)
:QDoubleValidator(bottom, top, decimals, parent){}
virtual void fixup(QString& input)const override{
input= QString::number(bottom(), 'f', decimals());
}
};
That way, you can just use your validator with any QLineEdit
like this:
lineEdit->setValidator(new MyDoubleValidator(100, 200, 2, lineEdit));
Note that, this way lineEdit
will emit editingFinished()
after finishing every edit, because even if the contents of QLineEdit
were not Acceptable
, our fixup()
implementation will always fix the contents to be Acceptable
.