Validation behaviour too confusing for end user
-
wrote on 23 Nov 2017, 11:56 last edited by JonB
I have inherited a body of code which uses a validator on
QLineEdit
s which allow a number with decimal point --- in fact specifically it's for a monetary amount. I know nothing about Qt's validation or how I'm intended to proceed. Here it is:class DecimalValidator(QtGui.QRegExpValidator): def __init__(self, parent=None): super().__init__(parent) self.setRegExp(QtCore.QRegExp("\d+(\.\d{1,2})?")) line = QLineEdit(self) line.setValidator(DecimalValidator()) line.editingFinished.connect(lambda: ensureValidDecimal(self))
The problem lies with
DecimalValidator
. It is trying to enforce that a valid money amount is 1 or more digits, optionally followed by a decimal point with 1 or 2 digits after it. Now, it appears thatQLineEdit.setValidator()
applies the validator logic while the user is typing into the line (doubtless what it's supposed to do!).- The user first types in
3.21
. All well & good. - But he realises he meant the amount to be
4.21
instead. What does he do? - Well, the natural thing to do is to move the caret to just before or after the leading
3
, delete it, and type in4
. - But when he tries to delete the
3
it refuses to vanish (with no feedback), at which point he becomes confused because he has no idea why he can't delete it. The validator is failing because we have said that the number must have at least one leading digit (which I do want, but only when he has finished editing). - It does not occur to him to first type in the
4
he now wants and then delete the3
, and I don't want him to have to do that.
The problem is the strict enforcement of the validator as he is typing in. I am not used to this, I am used to enforcing validators at end of editing stage. I can see the code calls a function for this via
QLineEdit.editingFinished.connect()
, which I guess is what I am used to. 3 questions:-
Can validation be delayed till end of editing rather than as you type, in some shape or form?
-
I can't see a way to write the validator regexp which still does the validation but allows the deletion of the leading digit if necessary. Can anyone else?
-
Assuming not, what do you think I should do here? I think I'm going to have open the validation at type-in time up to allow non-finally-acceptable input because of this issue. And then rely on
QLineEdit.editingFinished.connect()
to do definitive validation, right? In which case, I could either get rid of the regexp validator completely, or change it to"\d*(\.\d{1,2})?"
which at least ensures only digits & decimal point typed in. Opinions?
Furthermore, looking at existing code for
ensureValidDecimal()
(which is a bit convoluted to include here), I don't see that it "errors" or "rejects" invalid input. If I have to use theeditingFinished
signal to do post-editing validation, what is it supposed to do to "reject" the input? - The user first types in
-
@JNBarchan said in Validation behaviour too confusing for end user:
Can validation be delayed till end of editing rather than as you type, in some shape or form?
In principle Qt's validator provide this: http://doc.qt.io/qt-4.8/qvalidator.html#State-enum
As long as your validator returns QValidator::Intermediate, you can continue editing it until the string becomes QValidator::Acceptable.
The problem you here run into, seems that QRegExpValidator always starts validating from the beginning: If a string is a prefix of an Acceptable string, it is considered Intermediate. For example, "" and "A" are Intermediate for the regexp [A-Z][0-9] (whereas "_" would be Invalid). [1]
I don't know if there is any workaround here. I'd suggest writing your own validator based on QValidator. Then return intermediate as long as the string can still become valid. Otherwise return QValidator::Invalid.
When the string is a valid input, return QValidator::Acceptable.
Hope that helps.
-
@JNBarchan said in Validation behaviour too confusing for end user:
Can validation be delayed till end of editing rather than as you type, in some shape or form?
In principle Qt's validator provide this: http://doc.qt.io/qt-4.8/qvalidator.html#State-enum
As long as your validator returns QValidator::Intermediate, you can continue editing it until the string becomes QValidator::Acceptable.
The problem you here run into, seems that QRegExpValidator always starts validating from the beginning: If a string is a prefix of an Acceptable string, it is considered Intermediate. For example, "" and "A" are Intermediate for the regexp [A-Z][0-9] (whereas "_" would be Invalid). [1]
I don't know if there is any workaround here. I'd suggest writing your own validator based on QValidator. Then return intermediate as long as the string can still become valid. Otherwise return QValidator::Invalid.
When the string is a valid input, return QValidator::Acceptable.
Hope that helps.
wrote on 23 Nov 2017, 12:29 last edited by@aha_1980
Thank you for this. I will investigate and report back.However, may I ask regardless for an answer to: if, for whatever reason, I wish to do final validation in
QLineEdit.editingFinished
, since it's not like this returnsTrue
/False
to prevent leaving the edit control, I'm guessing my handler would be responsible for raising an error if it didn't like what it sees?Also, I don't suppose that
setInputMask()
unlikesetValidator()
only operates ateditingFinished
time rather than as the user types? -
@aha_1980
Thank you for this. I will investigate and report back.However, may I ask regardless for an answer to: if, for whatever reason, I wish to do final validation in
QLineEdit.editingFinished
, since it's not like this returnsTrue
/False
to prevent leaving the edit control, I'm guessing my handler would be responsible for raising an error if it didn't like what it sees?Also, I don't suppose that
setInputMask()
unlikesetValidator()
only operates ateditingFinished
time rather than as the user types?@JNBarchan said in Validation behaviour too confusing for end user:
However, may I ask regardless for an answer to: if, for whatever reason, I wish to do final validation in QLineEdit.editingFinished, since it's not like this returns True/False to prevent leaving the edit control, I'm guessing my handler would be responsible for raising an error if it didn't like what it sees?
You can call QLineEdit::hasAcceptableInput in that slot. I'm not sure if you should prohibit leaving the edit field, but at least you can disable the "Ok" button if the input is invalid. I have some dialogs acting like that (but I call hasAcceptableInput on every textChanged() signal to enable/disable the Ok button in a dialog.
-
wrote on 23 Nov 2017, 14:48 last edited by VRonin
- QRegExp is deprecated, use QRegularExpression
- In C++ the solution is trivial, you just need to reimplement the validator to transform Invalid input into intermediate input:
class LenientRegExpValidator : public QRegularExpressionValidator{ Q_OBJECT Q_DISABLE_COPY(LenientRegExpValidator) public: LenientRegExpValidator(QObject* parent = Q_NULLPTR) : QRegularExpressionValidator(parent){} LenientRegExpValidator(const QRegularExpression &re, QObject *parent = Q_NULLPTR) : QRegularExpressionValidator(re,parent){} QValidator::State validate(QString &input, int &pos) const Q_DECL_OVERRIDE{ const QValidator::State baseValidator = QRegularExpressionValidator::validate(input,pos); if(baseValidator ==QValidator::Invalid) return QValidator::Intermediate; return baseValidator; } };
-
- QRegExp is deprecated, use QRegularExpression
- In C++ the solution is trivial, you just need to reimplement the validator to transform Invalid input into intermediate input:
class LenientRegExpValidator : public QRegularExpressionValidator{ Q_OBJECT Q_DISABLE_COPY(LenientRegExpValidator) public: LenientRegExpValidator(QObject* parent = Q_NULLPTR) : QRegularExpressionValidator(parent){} LenientRegExpValidator(const QRegularExpression &re, QObject *parent = Q_NULLPTR) : QRegularExpressionValidator(re,parent){} QValidator::State validate(QString &input, int &pos) const Q_DECL_OVERRIDE{ const QValidator::State baseValidator = QRegularExpressionValidator::validate(input,pos); if(baseValidator ==QValidator::Invalid) return QValidator::Intermediate; return baseValidator; } };
wrote on 27 Nov 2017, 14:56 last edited by@VRonin said in Validation behaviour too confusing for end user:
QRegExp is deprecated, use QRegularExpression
Documentation observation:
In Qt docs, in http://doc.qt.io/qt-5/qregexp.html#details I see
Note: In Qt 5, the new QRegularExpression class provides a Perl compatible implementation of regular expressions and is recommended in place of QRegExp.
But in http://doc.qt.io/qt-5/qregexpvalidator.html#details I see no such admonition for using
QRegularExpressionValidator
instead. -
- QRegExp is deprecated, use QRegularExpression
- In C++ the solution is trivial, you just need to reimplement the validator to transform Invalid input into intermediate input:
class LenientRegExpValidator : public QRegularExpressionValidator{ Q_OBJECT Q_DISABLE_COPY(LenientRegExpValidator) public: LenientRegExpValidator(QObject* parent = Q_NULLPTR) : QRegularExpressionValidator(parent){} LenientRegExpValidator(const QRegularExpression &re, QObject *parent = Q_NULLPTR) : QRegularExpressionValidator(re,parent){} QValidator::State validate(QString &input, int &pos) const Q_DECL_OVERRIDE{ const QValidator::State baseValidator = QRegularExpressionValidator::validate(input,pos); if(baseValidator ==QValidator::Invalid) return QValidator::Intermediate; return baseValidator; } };
wrote on 27 Nov 2017, 16:36 last edited by JonBIn C++ the solution is trivial, you just need to reimplement the validator to transform Invalid input into intermediate input
OK, I have managed to implement this in PyQt for my Python (bit of a struggle, but done).
[As an aside, it's a bit more complicated than that. I presume I need 2 regular expressions in the
QValidator
, one for the reg exp which is as it is now to returnAcceptable
, and then a second one which allows no leading digit at all to returnIntermediate
, and then if it fails both (e.g. user types a letter, or two decimal points) returnInvalid
. Not sure how to do that asQValidator
allows just one expression insetRegularExpression()
which is used by the basevalidate()
... Am I supposed to change the reg exp viasetRegularExpression()
twice and call basevalidate()
twice each time in myvalidate()
override??]But ignoring that complication for the moment, what's the "point" of
Intermediate
? Once I have put in the code, instead of the user not being able to erase the single leading digit because it returnsInvalid
, he now can, just as if it returnsAcceptable
, as far as the Qt widget editing is concerned. So he can leave the field reading just.23
, which is not acceptable as a "final answer" to me. Where is the difference betweenAcceptable
&Intermediate
"expressed"/"acted upon"?I can only guess that the widget lets him type intermediate entry, and then it is up to me to go recheck for "truly"
Acceptable
, either on attempting to OK the Dialog or on attempting to exit editing the field. Is that right? The Qt validator is prepared to prevent me typing a truly illegal sequence into the widget as I go along, but it is not prepared to prevent me finishing editing with a still intermediate sequence? Then my problem is there are hundreds of such validators dotted all over the existing GUI code, with horrendousnesses to track them all down and think about changing behaviour, especially at the Dialog level but in general anyway....In short, given my requirement --- a final "decimal" should be 1+ leading digit (optionally followed by 1 or 2 decimal places, but that's not the problem), but while editing the user should be able to delete the single leading digit to replace it with another one --- can you give me an outline (doesn't have to be specific code) as to how you would actually handle this? It seems to me I should not be the only person who requires a monetary input like this, without leaving the user lost as to how to replace the leading digit?
Thank you, people!
-
In C++ the solution is trivial, you just need to reimplement the validator to transform Invalid input into intermediate input
OK, I have managed to implement this in PyQt for my Python (bit of a struggle, but done).
[As an aside, it's a bit more complicated than that. I presume I need 2 regular expressions in the
QValidator
, one for the reg exp which is as it is now to returnAcceptable
, and then a second one which allows no leading digit at all to returnIntermediate
, and then if it fails both (e.g. user types a letter, or two decimal points) returnInvalid
. Not sure how to do that asQValidator
allows just one expression insetRegularExpression()
which is used by the basevalidate()
... Am I supposed to change the reg exp viasetRegularExpression()
twice and call basevalidate()
twice each time in myvalidate()
override??]But ignoring that complication for the moment, what's the "point" of
Intermediate
? Once I have put in the code, instead of the user not being able to erase the single leading digit because it returnsInvalid
, he now can, just as if it returnsAcceptable
, as far as the Qt widget editing is concerned. So he can leave the field reading just.23
, which is not acceptable as a "final answer" to me. Where is the difference betweenAcceptable
&Intermediate
"expressed"/"acted upon"?I can only guess that the widget lets him type intermediate entry, and then it is up to me to go recheck for "truly"
Acceptable
, either on attempting to OK the Dialog or on attempting to exit editing the field. Is that right? The Qt validator is prepared to prevent me typing a truly illegal sequence into the widget as I go along, but it is not prepared to prevent me finishing editing with a still intermediate sequence? Then my problem is there are hundreds of such validators dotted all over the existing GUI code, with horrendousnesses to track them all down and think about changing behaviour, especially at the Dialog level but in general anyway....In short, given my requirement --- a final "decimal" should be 1+ leading digit (optionally followed by 1 or 2 decimal places, but that's not the problem), but while editing the user should be able to delete the single leading digit to replace it with another one --- can you give me an outline (doesn't have to be specific code) as to how you would actually handle this? It seems to me I should not be the only person who requires a monetary input like this, without leaving the user lost as to how to replace the leading digit?
Thank you, people!
wrote on 27 Nov 2017, 17:25 last edited by VRonin@JNBarchan said in Validation behaviour too confusing for end user:
I can only guess that the widget lets him type intermediate entry, and then it is up to me to go recheck for "truly" Acceptable
You can easily do this on
editingFinished()
signal. This also applies to the default behaviour ofQRegularExpressionValidator
if you don't type anything after the decimal separator
let's try this:
(again, sorry for C++ but I have no idea how you would subclass in Python)class LenientRegExpValidator : public QRegularExpressionValidator{ Q_OBJECT Q_DISABLE_COPY(LenientRegExpValidator) public: LenientRegExpValidator(QObject* parent = Q_NULLPTR) : QRegularExpressionValidator(parent){} LenientRegExpValidator(const QRegularExpression &re, QObject *parent = Q_NULLPTR) : QRegularExpressionValidator(re,parent){} QValidator::State validate(QString &input, int &pos) const Q_DECL_OVERRIDE{ const auto regExpr = regularExpression(); if(regExpr.pattern().isEmpty()) return Acceptable; const auto fullMatch = regExpr.match(input); if (fullMatch.hasMatch()) return QValidator::Acceptable; const auto partialMatch = regExpr.globalMatch(input, 0,QRegularExpression::PartialPreferFirstMatch); if(partialMatch.hasNext()) return QValidator::Intermediate; return QValidator::Invalid; } };
-
@JNBarchan said in Validation behaviour too confusing for end user:
I can only guess that the widget lets him type intermediate entry, and then it is up to me to go recheck for "truly" Acceptable
You can easily do this on
editingFinished()
signal. This also applies to the default behaviour ofQRegularExpressionValidator
if you don't type anything after the decimal separator
let's try this:
(again, sorry for C++ but I have no idea how you would subclass in Python)class LenientRegExpValidator : public QRegularExpressionValidator{ Q_OBJECT Q_DISABLE_COPY(LenientRegExpValidator) public: LenientRegExpValidator(QObject* parent = Q_NULLPTR) : QRegularExpressionValidator(parent){} LenientRegExpValidator(const QRegularExpression &re, QObject *parent = Q_NULLPTR) : QRegularExpressionValidator(re,parent){} QValidator::State validate(QString &input, int &pos) const Q_DECL_OVERRIDE{ const auto regExpr = regularExpression(); if(regExpr.pattern().isEmpty()) return Acceptable; const auto fullMatch = regExpr.match(input); if (fullMatch.hasMatch()) return QValidator::Acceptable; const auto partialMatch = regExpr.globalMatch(input, 0,QRegularExpression::PartialPreferFirstMatch); if(partialMatch.hasNext()) return QValidator::Intermediate; return QValidator::Invalid; } };
wrote on 27 Nov 2017, 21:28 last edited byYou can easily do this on editingFinished() signal.
But that's the bit I don't get! What do I do in the
editingFinished
handler? It's not like I can returnfalse
and then Qt would refuse leaving editing of the widget (which is exactly what I am used to in systems where a validator is evaluated on attempt to move out of editing instead of each character is typed).On top of that, the docs state:
Note that if there is a validator() or inputMask() set on the line edit and enter/return is pressed, the editingFinished() signal will only be emitted if the input follows the inputMask() and the validator() returns QValidator::Acceptable.
So if I'm still returning
Intermediate
for what they've typed, that says I won't get theeditingFinished
signal anyway. Not that I see that matters, since I don't get what I would do in it even if I did receive it.... -
You can easily do this on editingFinished() signal.
But that's the bit I don't get! What do I do in the
editingFinished
handler? It's not like I can returnfalse
and then Qt would refuse leaving editing of the widget (which is exactly what I am used to in systems where a validator is evaluated on attempt to move out of editing instead of each character is typed).On top of that, the docs state:
Note that if there is a validator() or inputMask() set on the line edit and enter/return is pressed, the editingFinished() signal will only be emitted if the input follows the inputMask() and the validator() returns QValidator::Acceptable.
So if I'm still returning
Intermediate
for what they've typed, that says I won't get theeditingFinished
signal anyway. Not that I see that matters, since I don't get what I would do in it even if I did receive it....@JNBarchan said in Validation behaviour too confusing for end user:
You can easily do this on editingFinished() signal.
But that's the bit I don't get! What do I do in the
editingFinished
handler? It's not like I can returnfalse
and then Qt would refuse leaving editing of the widget (which is exactly what I am used to in systems where a validator is evaluated on attempt to move out of editing instead of each character is typed).No, the QValidator works different. it forbids entering chars that lead to non-acceptable cases. for your example, it forbids entering a second . when there's already one. this is very convenient once you get used to.
On top of that, the docs state:
Note that if there is a validator() or inputMask() set on the line edit and enter/return is pressed, the editingFinished() signal will only be emitted if the input follows the inputMask() and the validator() returns QValidator::Acceptable.
So if I'm still returning
Intermediate
for what they've typed, that says I won't get theeditingFinished
signal anyway. Not that I see that matters, since I don't get what I would do in it even if I did receive it....in
editingFinished
you could enable an Ok button, for example. I dont know why you would disallow moving out of the edit? you can always get focus out when the user switches to another window. -
You can easily do this on editingFinished() signal.
But that's the bit I don't get! What do I do in the
editingFinished
handler? It's not like I can returnfalse
and then Qt would refuse leaving editing of the widget (which is exactly what I am used to in systems where a validator is evaluated on attempt to move out of editing instead of each character is typed).On top of that, the docs state:
Note that if there is a validator() or inputMask() set on the line edit and enter/return is pressed, the editingFinished() signal will only be emitted if the input follows the inputMask() and the validator() returns QValidator::Acceptable.
So if I'm still returning
Intermediate
for what they've typed, that says I won't get theeditingFinished
signal anyway. Not that I see that matters, since I don't get what I would do in it even if I did receive it....wrote on 28 Nov 2017, 08:17 last edited by@JNBarchan said in Validation behaviour too confusing for end user:
But that's the bit I don't get! What do I do in the editingFinished handler?
What I normally do is set the line edit background to red and maybe show a red QLabel to warn about the invalid output
that says I won't get the editingFinished signal anyway
Good spot. You can use textedited then
-
@JNBarchan said in Validation behaviour too confusing for end user:
But that's the bit I don't get! What do I do in the editingFinished handler?
What I normally do is set the line edit background to red and maybe show a red QLabel to warn about the invalid output
that says I won't get the editingFinished signal anyway
Good spot. You can use textedited then
wrote on 28 Nov 2017, 15:14 last edited by JonBThank you all for your input.
I have sat and thought about this carefully for a while. I am coming round to the conclusion that I cannot meet what I would desire.
I have no problem with the behaviours of
QValidator::Acceptable
&QValidator::Invalid
. But I do not see how the behaviour ofQValidator::Intermediate
helps me/meets my requirements. (Please note: I do understand how it works, that's not the issue.)Consider my example of a "decimal number":
\d+(\.\d{1,2})?
-
If user types a letter, it immediately returns
Invalid
and prevents the character being placed in the widget. Perfect, since that character can never be acceptable. -
What should I return if user deletes the single leading digit, in preparation for typing in a new one?
-
At present it returns
Invalid
, preventing the user from deleting. I have said I do not like this behaviour. So, I shall be changing over toIntermediate
... but how/when? -
If I return
Intermediate
instead ofInvalid
in all cases, this is simple. However, that allows the useless typing of a letter. It allows everything through, requiring me to check up more on completion. -
I start to think of only returning
Intermediate
instead ofInvalid
in certain cases, of the kind outlines in @VRonin's last posted code example. That seems possible, till I consider what code I would need. I would require something like a regular expression capturing the difference between "what is potentially heading in the right direction" as opposed to "is simply unacceptable" (e..g typing a letter). @VRonin has suggestedQRegularExpression::PartialPreferFirstMatch
, but from what I can see in the documentation (not tested) of "partial matches" these only allow for an "incomplete match which could be satisfied by appending further characters". That will not help with the kind of situation I am thinking of, where the user perform edits "in the start/middle of the string" to get to what he wants. I would have to think out a regular expression or code for every situation I can imagine as my definition of "intermediate" to achieve this, a non-trivial task.
I can see that Qt's
Intermediate
may work in this sense assuming the user types linearly from left to right --- which is what it seems to be designed for --- but not in my sense. I also realise upon careful reflection how difficult it is to express just what should beIntermediate
versusInvalid
.You people may be familiar & happy with how Qt validators work, but I (and my potential users) may not be attuned to its way of working. At least in my case of entering a "decimal number".
In light of the above I think I am left with "2.5" choices:
-
Make all
Invalid
s returnIntermediate
instead (coding too hard to distinguish specific cases). Then I probably need to do color-marking of "intermediate-value" widgets (how would I even do this from within existing class derived fromQValidator
, I don't see a method to get at the widget which is being validated?). Then I definitely would need to do "final" validation on, say, Dialog "OK" or whatever, but there are 50 dialogs with say an average of 5 widgets to validate on each one, there's no central place for me to track them all down to alter code? This is why I'm thinking I'm not going to be able to useIntemediate
. -
a. Put up with exactly the current regular expression & behaviour. The user who attempted to use the widget and needed to delete the first digit to change it to another got completely stuck and had no idea what was wrong/what he needed to do :( But hey ho, you guys seem to like the behaviour :)
b. Ask my stakeholder if I may change the validator to\d?(\.\d{1,2})?
This is my preferred solution. In return for allowing the leading-delete, it will allow through.23
, but provided the code can accept this it may be the simplest to resolve just this situation...
Those are my thoughts! I hope you're all fascinated :)
-
-
wrote on 28 Nov 2017, 15:32 last edited by
I'm afraid there's not a generic way. In your specific case, probably a
QDoubleValidator
instead of a regexp one might work better.
For other cases you'd probably need to return intermediate always and reimplementQValidator::fixup
to delete (or do something with it) the line if the input is invalid -
I'm afraid there's not a generic way. In your specific case, probably a
QDoubleValidator
instead of a regexp one might work better.
For other cases you'd probably need to return intermediate always and reimplementQValidator::fixup
to delete (or do something with it) the line if the input is invalidwrote on 28 Nov 2017, 16:39 last edited by JonB@VRonin
Yup, thanks for your confirmation & patience.I might have a look at
QDoubleValidator
, in case it internally handles my case better. Just to complicate things, I know it's not your area, but because I am Python/PyQt what I actually need to validate is that it satisfies an internal PyQt type namedDecimal
, which is not the same as double, and isn't even documented as to what format it parses...! :(One final (honest!) question, inspired by something I mentioned above and your earlier comment:
What I normally do is set the line edit background to red and maybe show a red QLabel to warn about the invalid output
How (what code approach do you take) to achieve this in Qt? So far as I can see, one uses
QLineEdit::setValidator()
to set the validator, so a line edit can see its validator, butQValidator
does not have a member to reference theQLineEdit
it has been called from? And I suspect there cannot be one, as you could associate the sameQValidator
object with multipleQLineEdits
, if you chose to do so. So when my overriddenQValidator::validate()
wants to returnIntermediate
, how can I have code there to know which widget to affect?In the validator model I am accustomed to from another language/library, there is a one-to-one relationship between a control and its validator, so you can access one from the other. But I think that's not the case in Qt, so how do you manage it? I can only see creating a "lookup" table for each dialog so that I know the widget from the validator (assuming I stick to one-to-one), or maybe you sub-class
QValidator
and add a member for the associatedQLineEdit
, and that's going to be real messy for me.... -
@VRonin
Yup, thanks for your confirmation & patience.I might have a look at
QDoubleValidator
, in case it internally handles my case better. Just to complicate things, I know it's not your area, but because I am Python/PyQt what I actually need to validate is that it satisfies an internal PyQt type namedDecimal
, which is not the same as double, and isn't even documented as to what format it parses...! :(One final (honest!) question, inspired by something I mentioned above and your earlier comment:
What I normally do is set the line edit background to red and maybe show a red QLabel to warn about the invalid output
How (what code approach do you take) to achieve this in Qt? So far as I can see, one uses
QLineEdit::setValidator()
to set the validator, so a line edit can see its validator, butQValidator
does not have a member to reference theQLineEdit
it has been called from? And I suspect there cannot be one, as you could associate the sameQValidator
object with multipleQLineEdits
, if you chose to do so. So when my overriddenQValidator::validate()
wants to returnIntermediate
, how can I have code there to know which widget to affect?In the validator model I am accustomed to from another language/library, there is a one-to-one relationship between a control and its validator, so you can access one from the other. But I think that's not the case in Qt, so how do you manage it? I can only see creating a "lookup" table for each dialog so that I know the widget from the validator (assuming I stick to one-to-one), or maybe you sub-class
QValidator
and add a member for the associatedQLineEdit
, and that's going to be real messy for me....wrote on 28 Nov 2017, 16:50 last edited by@JNBarchan said in Validation behaviour too confusing for end user:
I might have a look at QDoubleValidator, in case it internally handles my case better.
QDoubleValidator
basically just usesQLocale::toDouble
so should be more lenient.How (what code approach do you take) to achieve this in Qt?
I normally change it to red when the user tries to submit a form
-
@JNBarchan said in Validation behaviour too confusing for end user:
I might have a look at QDoubleValidator, in case it internally handles my case better.
QDoubleValidator
basically just usesQLocale::toDouble
so should be more lenient.How (what code approach do you take) to achieve this in Qt?
I normally change it to red when the user tries to submit a form
wrote on 28 Nov 2017, 17:01 last edited by JonB@VRonin said in Validation behaviour too confusing for end user:
How (what code approach do you take) to achieve this in Qt?
I normally change it to red when the user tries to submit a form
Sorry, this is not what I was asking. Ahh! Do you mean, you don't turn it red during
QValidator::validate()
, so don't access theQLineEdit
from there; instead duringQDialog:onOK()
(or whatever it is,accept()
) you enumerate eachQLineEdit
in the dialog and call itsQLineEdit::hasAcceptableInput()
? So you never try to map from validator to widget? -
@VRonin said in Validation behaviour too confusing for end user:
How (what code approach do you take) to achieve this in Qt?
I normally change it to red when the user tries to submit a form
Sorry, this is not what I was asking. Ahh! Do you mean, you don't turn it red during
QValidator::validate()
, so don't access theQLineEdit
from there; instead duringQDialog:onOK()
(or whatever it is,accept()
) you enumerate eachQLineEdit
in the dialog and call itsQLineEdit::hasAcceptableInput()
? So you never try to map from validator to widget?wrote on 28 Nov 2017, 17:18 last edited by@JNBarchan said in Validation behaviour too confusing for end user:
ou enumerate each QLineEdit in the dialog and call its QLineEdit::hasAcceptableInput()? So you never try to map from validator to widget?
Correct. The validator's job is not to take care of how an item is displayed. That's either the job of the linedit or its parent (either via connecting the textEdited() signal, using fixup() to clear invalid input and then using editingFinished() or uppon submit of form (e.g. when you press the Ok button at the end of a dialog)
-
@JNBarchan said in Validation behaviour too confusing for end user:
I might have a look at QDoubleValidator, in case it internally handles my case better.
QDoubleValidator
basically just usesQLocale::toDouble
so should be more lenient.How (what code approach do you take) to achieve this in Qt?
I normally change it to red when the user tries to submit a form
wrote on 29 Nov 2017, 09:48 last edited by@VRonin said in Validation behaviour too confusing for end user:
@JNBarchan said in Validation behaviour too confusing for end user:
I might have a look at QDoubleValidator, in case it internally handles my case better.
QDoubleValidator
basically just usesQLocale::toDouble
so should be more lenient.Changed over to
QDoubleValidator
. Whether it implements via a different regular expression from the one I inherited or implements validation with dedicated code, either way it gives me/my user a more pleasant editing experience, allowing the original issue of being able to delete a lone leading digit. It also of course "feels" better.So thank you, that will do nicely here after all this discussion (though that was worthwhile so that I now understand how Qt validators work).
1/18