PDA

View Full Version : QLineEdit set min max range?



whitefurrows
20th May 2006, 17:57
Hi,

how can i set a Validator to a QLineEdit that accept only values between 1.00 and 16.00 ?

Thanks in advance,

Whitefurrows

jpn
20th May 2006, 18:05
QSpinBox (http://doc.trolltech.com/4.1/qspinbox.html) (or QDoubleSpinBox (http://doc.trolltech.com/4.1/qdoublespinbox.html)) would have the required behaviour, out of the box... ;)

whitefurrows
20th May 2006, 18:21
I need a clear input field like a QLineEdit. I can't use a QSpinBox or QDoubleSpinBox because have a button on the right side.

One more tip ?

jacek
20th May 2006, 19:57
Then use QDoubleValidator or QRegExpValidator (regexp should be something like "(?:1[0-5]|[1-9])(?:[.,]\\d\\d?)?|16(?:[.,]00?)?").

whitefurrows
21st May 2006, 00:24
Hi,

that's great your regexp work fine. I read the doc for QRegExp but i dont know what you do. Can you describe how your regexp work and i understand that. The problem is i have many other ranges to set e.g. 0-50, 15-32, 65-105 and i can't change your regexp.

How can i set a QDoubleValidator its's easey, but my code don't work. I can set values out of range. Why?

lineEdit->setValidator(new QDoubleValidator( 1.00, 16.00, 2, lineEdit));

Greetings,

Whitefurrows

jacek
21st May 2006, 00:48
Can you describe how your regexp work and i understand that. The problem is i have many other ranges to set e.g. 0-50, 15-32, 65-105 and i can't change your regexp.
In such case, IMO, it would be better if you create your own validator class, because regexps aren't very readable.

Anyway, suppose you want a regexp for 65-105 range. Valid numbers are:
65, 66, 67, 68, 69, 70, ..., 79, 80, ..., 89, 90, ..., 99, 100, 101, 102, 103, 104, 105

There are three possibilities:
6 and one of {5, 6, 7, 8, 9} -> 6[5-9]
one of {7, 8, 9} and a digit -> [7-9]\\d
10 and one of {0, 1, 2, 3, 4, 5} -> 10[0-5]
and you just have to join them: 6[5-9]|[7-9]\\d|10[0-5]


How can i set a QDoubleValidator its's easey, but my code don't work. I can set values out of range. Why?
Because you can enter 1500.00e-2, which is a valid number.

whitefurrows
21st May 2006, 01:09
OK i have understand how work the regexp, thank you.

I think really it's better to write my own validator class.


class myDoubleValidator : public QDoubleValidator
{
public:
myDoubleValidator( double bottom, double top, int decimals, QObject* parent = 0)
: QDoubleValidator( bottom, top, decimals, parent){}

QValidator::State validate ( QString & input, int &pos ) const
{
if ( input.isEmpty() || input == "." )
return Intermediate;
//I'm not sure what can i do here
return Invalid;
}

return Acceptable;
}
};


Can you help me please?

jacek
21st May 2006, 15:04
Take a look at QDoubleValidator::validate() implementation (it's in %QTDIR%/src/gui/widgets/qvalidator.cpp). All you have to do is to remove the part that handles the exponent.

whitefurrows
21st May 2006, 16:11
I don't want change orginal files. I try this:


class MyDoubleValidator : public QDoubleValidator
{
public:
MyDoubleValidator( double bottom, double top, int decimals, QObject* parent = 0)
: QDoubleValidator( bottom, top, decimals, parent)
{}

QValidator::State QDoubleValidator::validate(QString & input, int &) const
{
QRegExp empty(QString::fromLatin1("-?\\.?"));
if (input.contains(' '))
return Invalid;
if (b >= 0 && input.startsWith(QLatin1Char('-')))
return Invalid;
if (empty.exactMatch(input))
return Intermediate;
bool ok = true;
double entered = input.toDouble(&ok);
int nume = input.count('e', Qt::CaseInsensitive);
if (!ok) {
// explicit exponent regexp
QRegExp expexpexp(QString::fromLatin1("[Ee][+-]?(\\d*)$"));
int eePos = expexpexp.indexIn(input);
if (eePos > 0 && nume == 1) {
QString mantissa = input.left(eePos);
entered = mantissa.toDouble(&ok);
if (!ok)
return Invalid;
if (expexpexp.cap(1).isEmpty())
return Intermediate;
} else if (eePos == 0) {
return Intermediate;
} else {
return Invalid;
}
}

int i = input.indexOf('.');
if (i >= 0 && nume == 0) {
// has decimal point (but no E), now count digits after that
i++;
int j = i;
while(input[j].isDigit())
j++;
if (j - i > d)
return Intermediate;
}

if (entered < b || entered > t)
return Intermediate;
return Acceptable;
}
};


but i can't compile!

jacek
21st May 2006, 16:21
I try this:
You're on the right track.

It should be:

class MyDoubleValidator : public QDoubleValidator
{
public:
MyDoubleValidator( double bottom, double top, int decimals, QObject* parent = 0)
: QDoubleValidator( bottom, top, decimals, parent)
{}

QValidator::State validate(QString & input, int &) const
{
// we don't have the access to private members of QDoubleValidator,
// so we must simulate them:
const double b = bottom();
const double t = top();
const int d = decimals();

QRegExp empty(QString::fromLatin1("-?\\.?"));
if (input.contains(' '))
return Invalid;
...
}
};

whitefurrows
21st May 2006, 18:24
Hi,

that's work fine. Thank you for your great help.

Greetings,

Whitefurrows

whitefurrows
29th May 2006, 17:53
Hi,

sorry i have trouble with my own QDoubleValidator, i set a Range 5-25 but i can't type 15 in to the QLineEdit:
myLineEdit->setValidator(new MyDoubleValidator( 5, 25, 2, myLineEdit));

Can anybody help me?

Greetings,

Whitefurrows


class MyDoubleValidator : public QDoubleValidator
{
public:
MyDoubleValidator( double bottom, double top, int decimals, QObject* parent = 0)
: QDoubleValidator( bottom, top, decimals, parent){}

QValidator::State validate(QString & input, int &) const
{
const double b = bottom();
const double t = top();
const int d = decimals();

QRegExp empty(QString::fromLatin1("-?\\.?"));
if (input.contains(' '))
return Invalid;
if (b >= 0 && input.startsWith(QLatin1Char('-')))
return Invalid;
if (empty.exactMatch(input))
return Intermediate;

bool ok = false;
double entered = input.toDouble(&ok);
if (!ok) return Invalid;

int nume = input.count('e', Qt::CaseInsensitive);

int i;
if (input.contains(','))
i = input.indexOf(',');
else
i = input.indexOf('.');

if (i >= 0 && nume == 0) {
i++;
int j = i;
while(input[j].isDigit())
j++;
if (j - i > d)
return Invalid;
}

if (entered < b || entered > t)
return Invalid;

return Acceptable;
}
};

jacek
29th May 2006, 18:18
The problem is here:
if (entered < b || entered > t)
return Invalid;
If the allowed range is 5--25, then "1" should be an intermediate value, not invalid one.
It should be probably:
if( entered < b ) {
return Intermediate;
}
else if( entered > t ) {
return Invalid;
}

whitefurrows
2nd June 2006, 23:15
Hi,

sorry i don't have get a notification. That's right, but the user can put wrong values to the QLineEdit.

What can i do?

Greetings,

Whitefurrows

jacek
3rd June 2006, 00:24
That's right, but the user can put wrong values to the QLineEdit.
The problem is that line edit can loose focus when it contains an intermediate value. IMO you should ask the Trolls whether this is a correct behavior.

whitefurrows
4th June 2006, 01:36
Hi,

thank's to you. You know a way how can i set focus to a QLineEdit as long as contains an intermediate value?

Greetings

Whitefurrows

jpn
4th June 2006, 06:54
There are many ways to do that. You could override line edit's focusOutEvent(), use an event filter, or install an event filter even on the application. In all cases, you'll just have to ask the validator for it's state and then set the focus back on the line edit when appropriate.

whitefurrows
4th June 2006, 13:23
Hi,

can you help me to do that, please?

I try that:


protected:
QLineEdit focusOutEvent(QFocusEvent* event) const;


QLineEdit MyWidget::focusOutEvent(QFocusEvent* event) const{
const QObject* ob=QObject::sender();
int i =0;
while (ob!=lineEditList[i] && i<lineEditList.size())
i++;

if(LineEdit Validator state == intermediate) //How can i do that?
leList[i]->setEditFocus(true);
}

Thanks in advance,

Whitefurrows

jpn
4th June 2006, 18:01
The focus out event could look for example something like this:


void MyLineEdit::focusOutEvent(QFocusEvent* event)
{
// check validator state
int pos = 0;
QValidator::State state = validator()->validate(text(), pos);

if (state == QValidator::Intermediate)
{
// keep focus if intermediate
setFocus();
}
else
{
// otherwise call base class implementation and let it
// handle focus out actions (so cursor stops blinking etc.)
QLineEdit::focusOutEvent(event);
}
}


If you have difficulties in subclassing QLineEdit, I suggest you to switch back to your favourite C++ book and learn the secrects of inheritance.. ;)

whitefurrows
4th June 2006, 19:12
Hi,

the problem is i can't subclassing QLineEdit. I use the designer and the designer use the QLineEdit and not MyLineEdit.

Sorry my stupid question i'm a beginner and learn. Please help me one more time.

Greetings,

Whitefurrows

jpn
4th June 2006, 19:15
You can use the subclassed line edit widget by promoting it as custom widget in the designer. See the context menu of the line edit.

whitefurrows
5th June 2006, 15:43
Hi,

thank you that's work, but i have one more problem MyLineEdit keep focus if intermediate but if i press button "Save" can i save the data(that's wrong) and MyLineEdit keep focus.

Is that OK? What can i do?

Greetings,

Whitefurrows

jpn
5th June 2006, 16:12
Sorry, what's the problem? You'll have to explain a bit more clearly. "Can I save the data" is quite an abstract concept..

whitefurrows
5th June 2006, 19:37
Sorry, ok i try it. I have many QLineEdit's on a QWidget and a Button. When the user push the butten, then store the programm the values from the QlineEdit's to the database. The user can store the data always, but that is wrong. I wont the user can save the data only if all QlineEdit's contain right values?

You know what i mean?

jpn
5th June 2006, 20:18
You could check the validator states whenever QLineEdit::textChanged() signal is emitted. Or you could emit signals (sending state as a parameter) from the validators whenever they are asked to validate. There are many possibilities... But anyway, you have to somehow keep track of the validator states and enable/disable the button when appropriate.

Edit: just a side note.. have you looked the possibility of using for example QSqlTableModel + QTableView and a custom delegate to provide suitable editor..?

whitefurrows
5th June 2006, 21:53
Hi,

thank you. I know how can i check the validator states whenever QLineEdit::textChanged() signal is emitted and enable/disable the button.

I have one last question, i think it's better the QLineEdit can't lost focus as long as the validator states = Intermediate and the user can do nothing else.

You kow how can i do that?

Thanks in advance,

Whitefurrows

jpn
6th June 2006, 06:22
It's not possible to prevent user from pressing the button by forcing the focus to a line edit. If you ever have to prevent user from doing something, disabling widgets (or blocking with a modal dialog) is the way to go in most cases.

I get the feeling that there is some misunderstanding of the concept "focus" here. A widget having focus just receives all keyboard input events (unless some other widget has grabbed the keyboard, but that's a whole different story). You can still eg. mouse click over any other widget and so on..

whitefurrows
10th June 2006, 21:16
Hi,

sorry the late answer, but i have a long time read the doc and written code. I thing the right way is disabling widgets.

I do this to check QValidator::State:


int pos = 0;
QValidator::State state;
QList<QLineEdit *> leList= this->findChildren<QLineEdit *>();
for (int i=0;i<leList.size();i++){
state = leList[i]->validator()->validate(leList[i]->text(), pos);
if(state == QValidator::Intermediate && leList[i]->text() != ""){
//disabling widgets
}
}

That's worke fine, but i get a error if a QLineEdit without QValidator.

How can i check if QLineEdit Validator set, or you know a other solution?

Greetings,

Whitefurrows

jacek
10th June 2006, 21:26
How can i check if QLineEdit Validator set, or you know a other solution?


const QValidator * QLineEdit::validator () const
Returns a pointer to the current input validator, or 0 if no validator has been set.

So this should work:
...
QList<QLineEdit *> leList= this->findChildren<QLineEdit *>();
for (int i=0;i<leList.size();i++){
if( leList[i]->validator() != 0 ) {
state = leList[i]->validator()->validate(leList[i]->text(), pos);
...
}
}

whitefurrows
10th June 2006, 23:51
Hi,

now work all fine. Thank you very much. Your help was great!!!

Greetings,

Whitefurrows