Walidacja danych w lineEditach

0

Chciałbym poradzić się Was jakbyście rozwiązali pewien problem wprowadzania danych w lineEdit'y (dokładnie chodzi mi tutaj o rozwiązanie oparte o c++/Qt, ale myślę, że rozwiązania Javie czy w C# to nie duża różnica.. (może być nawet "rozbudowany" pseudokod)).

Efekt końcowy

Wprowadzane dane w lineEdity to liczby typu double, od 0 do 10, których przykłady wyglądają tak:

0.0
5.1
7.6
10.2
10.7c

user image

gdzie możliwe jest wprowadzenie wyłącznie kropki, a literę c można wprowadzić wyłącznie w momencie gdy wcześniej została wpisana liczba 10. Dodatkowo chcialbym uzyskać taki efekt, że jak mamy powiedzmy 5 linEditów i przechodzę po nich za pomocą tabulatora to po wpisaniu powiedzmy 5, ta liczba ma być uzupełniona do "pełnej" formy czyli 5.0 (a w przypadku 10c ma być 10.0c).

Jak taki efekt "najestetyczniej" uzyskać ?

Aktualnie mam zastosowany jakieś prymitywne wyrażenie regularne, które pozwala wprowadzić cyfry, kropke i literke c (ale nie spełnia to wszystkich powyższych warunków..). Pewnie przy kombinowaniu z if'ami, porównywaniem etc.. uzyskałbym końcowy efekt, ale już teraz wiem, że nie będzie to wyglądać za elegancko ..

Dlatego chciałbym zapytać się Was jaki Wy mielibyście pomysł na rozwiązanie tego problemu ?

ps. Ten wątek ma cel edukacyjny dla mnie ( i mam nadzieje dla innych :) ), bo inaczej pewnie to skalecze..

dodanie znacznika <code> - fp

0
  1. nie pisz na priva
  2. używaj tagów na których co zależy (brak taga qt, który jest ważniejszy java, która jest tylko dodatkiem)
  3. pokaż kod bo na 90% coś przekombinowałeś

http://qt-project.org/doc/qt-5.0/qtgui/qdoublevalidator.html#Notation-enum

0

@MarekR22 - Dzięki za odpowiedź! (ps. Ja na priv pisałem poniekąd z propozycją "zleceniową", ale nvm .. :) )

Jeszcze dzisiaj poprawiałem funkcjonowanie klawisza Tab, który nie chciał współpracować, tak jak inne "zwykłe" klawisze.. Prawdopodobnie wystąpił tutaj problem opisany w innym topicu przez @liske1 ( http://4programmers.net/Forum/C_i_C++/222548-qt_klawisze_strzalek_nie_dzialaja ).

Wracając jednak do meritum.. i do założeń z pierwszego postu..
Na samym początku miałem wyłącznie zastosowane jedno wyrażenie regularne, o którym już wspominałem w pierwszym poście..

EDIT:

 QRegExp rexNumbers("\\d{2}\\.[0-9]|^10c$|^10\\.[0-9]c");
QRegExpValidator *validatorNumber = new QRegExpValidator(rexNumbers,NULL);

Defacto nadal stosuje to wyrażenie jako filtr przy wprowadzaniu danych.. Z tym, że nie spełnia to całościowo wymaganych założeń, ponieważ można wpisać 9.0c a tylko dla 10-tki powinna być taka możliwość.. (niestety nie potrafię przygotować takiego wyrażenia, które by to zapewniało.. Nawet nie wiem czy nawet jest to możliwe :P)

EDIT:

Poniżej załączam poprawiony kod. Okazuje się, że nawet spełnia to założenia z pierwszego posta :) Pytanie teraz brzmi jak to można zrobić lepiej :P (?)

**Brakuje tylko jednej rzeczy... **Mianowicie jak pewnie zauważyliście powyższy regEx jest dość nieestetyczny.. Został on właśnie rozbudowany, ale nadal brakuje walidacji np. w momencie gdy pierwsza cyfra jest zerem (0). Wtedy powinno dać się wpisać od razu kropkę i dalszą część. To samo dotyczy jedynki (1) - jedyna możliwość to zero (0). Zastanawiam się czy można tak uzupełnić powyższe wyrażenie regularne aby te ewentualności były uwzględnione..?..

 bool MyQLineEdit::eventFilter(QObject * object, QEvent * event)
{
    if(object == this && event->type() == QEvent::KeyPress) {
        QKeyEvent * keyEvent = static_cast<QKeyEvent *>(event);
        if(keyEvent->key() == Qt::Key_Tab) {

            if(!text().contains(".") && !text().contains("10c") && text().length()>0){
                QString validTxt = this->text() ;
                validTxt+= ".0";
                this->setText(validTxt);
            }
            else if(text().contains(".")){
                int n = this->text().size();
                QString lastChar = this->text().data()[n-1];
                qDebug() << lastChar;

                if(lastChar == ".") {
                    QString validTxt = this->text() ;
                    validTxt+= "0";
                    this->setText(validTxt);
                }
            }
            else if(text().contains("10c")){
                QString validTxt = "10.0c";
                this->setText(validTxt);
            }

            this->focusNextChild();
            return true;
        } else
            return false;
    }
    return false;
}
1
MyValidator::MyValidator(QObject *parent) :
    QDoubleValidator(0,10.0,1,parent)
{
}

QValidator::State MyValidator::validate(QString &str, int &pos) const
{
    State result;
    if (str.endsWith('c',Qt::CaseInsensitive)) {
        QString a(str.left(str.length()-1));
        int newPos = qMin(pos,a.length());
        if (newPos==0) {
            pos =newPos;
        }
        result = QDoubleValidator::validate(a,newPos);
        if (result==Acceptable) {
            bool ok;
            double value = toDouble(a, &ok);
            if (!qFuzzyCompare(value, 10.0) && ok) {
                result = Intermediate;
            }
            str = a+'c';
        } else if (result==Intermediate) {
            str = a+'c';
        } else {
            str = a;
        }
    } else {
        result = QDoubleValidator::validate(str,pos);
        if (result==Acceptable) {
            bool ok;
            double value = toDouble(str, &ok);
            if (qFuzzyCompare(value, 10.0) && ok) {
                // domacaj się końcowego "c"
                result =Intermediate;
            }
        }
    }
    return result;
}

void MyValidator::fixup(QString &str) const
{
    double value;
    if (str.endsWith('c', Qt::CaseInsensitive)) {
        value = toDouble(str.left(str.length()-1));
    } else {
        value = toDouble(str);
    }
    value = qBound(0.0, value, 10.0);
    str = locale().toString(value,'f',1);
    value = toDouble(str);
    if(qFuzzyCompare(value, 10.0)) {
        str += 'c';
    }
}

double MyValidator::toDouble(const QString &v, bool *ok) const
{
    bool localOk;
    double result = locale().toDouble(v, &localOk);
    // fallback to global or C locale:
    if (!localOk) {
        result = v.toDouble(&localOk);
    }
    if (ok)
        *ok = localOk;
    return result;
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1