PDA

View Full Version : Some QComboBox and custom QValidator background



frankiefrank
3rd March 2011, 15:22
I'm trying to understand how the validator framework works with a combo box.

The documentation of QComboBox explains how to set a validator, and the QValidator documentation explains how a validator would work (and also how to subclass one).

That's great but now that I have my custom validator and it's set to the combo box, I can't understand how the combo box interacts with it. Is the "validate" method I wrote called behind the scenes? If so, when? Or am I supposed to cast the QValidator to my own custom type and run the custom validate method on my own?

If anyone can help out with a little background and hopefully a little code to illustrate, I'd be grateful.

Thanks,
Frankie

high_flyer
3rd March 2011, 15:28
Do you understand what virtual method is?

frankiefrank
3rd March 2011, 15:29
Yes, I understand that.

high_flyer
3rd March 2011, 15:35
Well if you do, then you should be able to answer that:

I can't understand how the combo box interacts with it. Is the "validate" method I wrote called behind the scenes?
Since QCombox will call the validate() method of the QValidator instance you gave it, and if is your custom QValidator it will be your version of it.

frankiefrank
3rd March 2011, 15:54
First of all, the documentation does not state which data is being validated and when. Does the validation logic fire when I'm leaving focus, when I'm selecting an item from the existing list? When I'm calling addItem / insertItem programatically?

And since you brought up the virtual method: I do have a follow up question. My custom validator validates a string but isn't based on regular expression or on numeric validation. I inherited from RegExpValidator but I don't really understand why I don't see it called:



// Header
class ValuesRangeValidator : public QRegExpValidator
{
public:
ValuesRangeValidator(QObject * parent);
QValidator::State validate(const QString &valueToValidate, int &pos);
};

// Implementation
ValuesRangeValidator::ValuesRangeValidator(QObject * parent)
: QRegExpValidator(parent)
{
}

QValidator::State ValuesRangeValidator::validate(const QString &valueToValidate, int &pos)
{
bool valid = someValidationCode(valueToValidate);
return valid ? Acceptable : Invalid;
}

high_flyer
3rd March 2011, 16:24
First of all, the documentation does not state which data is being validated and when.
I don't agree with that statement.
If you read the docs for QComboBox::validator() you will see:

Returns the validator that is used to constrain text input for the combobox.
So it tells me, that during text input (which es every time you edit the text) the validator will be applied, which, makes sense too.

Now:

Does the validation logic fire when I'm leaving focus, when I'm selecting an item from the existing list? When I'm calling addItem / insertItem programatically?
That is also in the docs, but you have to pay attention:
Since we are dealing with an editable QComboBox, it has a QLineEdit.
So it means, when you input text, you are doing the input in to it QLineEdit.
That means, that your validator is applied by the QLineEdit.
Lets see what we can find there:


You can change the text with setText() or insert(). The text is retrieved with text(); the displayed text (which may be different, see EchoMode) is retrieved with displayText(). Text can be selected with setSelection() or selectAll(), and the selection can be cut(), copy()ied and paste()d. The text can be aligned with setAlignment().

When the text changes the textChanged() signal is emitted; when the text changes other than by calling setText() the textEdited() signal is emitted; when the cursor is moved the cursorPositionChanged() signal is emitted; and when the Return or Enter key is pressed the returnPressed() signal is emitted.

When editing is finished, either because the line edit lost focus or Return/Enter is pressed the editingFinished() signal is emitted.

Note that if there is a validator set on the line edit, the returnPressed()/editingFinished() signals will only be emitted if the validator returns QValidator::Acceptable.


Ok, I agree, that it doesn't answer your question in a nice one block, and that you have to apply some thought to see how this relates to your case.
But you can't expect the documentation to answer everything in the right way for each case.
But as you can see, the information is there, one just needs to invest in reading it ;-)


I inherited from RegExpValidator but I don't really understand why I don't see it called:
Hmm..
How did you check to know if its being called?

frankiefrank
3rd March 2011, 16:45
First of all thank you for your time and attention, and for bringing up the relevant documentation.

I'm sorry but even after reading about the different types of signals emitted from the lineEdit control I can't "guess" the behavior of an editable QComboBox just because it has a lineEdit member. For example, where does it say that validation is even called upon leaving focus of the combo's lineEdit?

I don't expect the documentation to answer "every question" for "every case". I stand by what I said that the documentation about the integration of a validator and a combox is almost not there (unless you know how the combo box wraps the signals emitted from its lineEdit members).

I put a breakpoint in my validate method to see if it's called at any point during my UI/programmatic interaction. I'm not seeing any calls so I'm guessing something in my wiring is wrong.

This piece of documentation:


"Note that if there is a validator set on the line edit, the returnPressed()/editingFinished() signals will only be emitted if the validator returns QValidator::Acceptable."
still leaves me wondering why I'm not seeing the call.

high_flyer
3rd March 2011, 16:55
For example, where does it say that validation is even called upon leaving focus of the combo's lineEdit?
Here (QLineEdit):

When editing is finished, either because the line edit lost focus or Return/Enter is pressed the editingFinished() signal is emitted.
And since the validator is applied during text input, and because finishing the text input through focus change is part of the input, the validator should be called as result of focus leave.


I put a breakpoint in my validate method to see if it's called at any point during my UI/programmatic interaction. I'm not seeing any calls so I'm guessing something in my wiring is wrong.
Ok, that is the right way to do it.
Hmm...
Can you post the code where you set your validator?

frankiefrank
3rd March 2011, 21:03
Here's the combo box related code:



// Initizalize Y axis controls
mYScalePresets = QStringList()
<< "some"
<< "presets"
<< "here";

ui.cmbYAxis->setDuplicatesEnabled(false);
ui.cmbYAxis->addItems(mYScalePresets);

ui.cmbYAxis->insertSeparator(ui.cmbYAxis->count()); // Insert separator at the end
ui.cmbYAxis->setValidator(new ValuesRangeValidator(ui.cmbYAxis));
ui.cmbYAxis->setInsertPolicy(QComboBox::InsertAtBottom);

ui.cmbYAxis->setCurrentIndex(0);


I'lll clarify the two issues I have:
1. I want to see that the validator code is executed when I'm putting text in and clicking Enter.
2. The behavior I would eventually want to achieve is to interferen to at the point of leaving focus. I want to add the item to the combo if its text is valid.

Thanks again for your assistance.

Added after 20 minutes:

OK, I've found the reason for the 1st issue: and it did come down to the virtual method after all!

I've used the wrong signature:



// WRONG:
// QValidator::State validate(const QString &valueToValidate, int &pos);

// Correct:
QValidator::State validate(QString &valueToValidate, int &pos) const;



But now I see that perhaps this whole approach is wrong for me because it would be very hard for me to code all the conditions for the "Intermediate" state. Can you try and help out with the 2nd issue?

Added after 22 minutes:

Another scenario that require an intervention point that I still don't know to find:
When manually entering data, to limit the amount of items (for example, if passed 10, remove the first).

Is there a solution I'm not seeing or does this require subclassing of the combobox?

frankiefrank
9th March 2011, 16:11
Just wanted to update with what I ended up doing, in case someone has a similar situation.

First: I decided that the validator framework is not right for me, since my intermediate state is too complex to be defined by a reg ex.
Second: I also decided not to do anything when leaving focus, instead only deal with entering new/existing data in the combo's line-edit OR selecting an existing option from the combo.

SO - to make sure I'm validating the entered input, I've used an eventFilter method to catch pressing on Enter/Return, and wired the method to the combo. Now I can control validation and decide if I want to add the item / or select an existing item, or ignore the whole thing altogether.

Thanks for the help!