Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Show Tooltip on wrong input in QLineEdit
QtWS25 Last Chance

Show Tooltip on wrong input in QLineEdit

Scheduled Pinned Locked Moved General and Desktop
16 Posts 3 Posters 19.4k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • J Offline
    J Offline
    jaydeep17
    wrote on 14 May 2012, 18:43 last edited by
    #1

    I have a QLineEdit, on which I have set a QRegExpValidator.
    Now I want that whenever the user tries to enter invalid input, the tooltip of the QLineEdit should show up, but I'm not getting any method to implement it.

    Thanx :)

    1 Reply Last reply
    0
    • K Offline
      K Offline
      Keozon
      wrote on 15 May 2012, 01:15 last edited by
      #2

      I could be wrong, but I don't think it is possible (or reasonably so) to implement such a feature using the Validator. In order to do something like that, you would need a signal emitted from the QValidator when an incorrect input is tried. The only signal QValidator can emit is destroyed().

      I think the only way to handle this is by using the textEdited signal from QLineEdit, which will emit every time the value is changed (e.g, character entered). You could then check it against a regex and if it isn't valid, emit a custom signal to a child widget that would sit in the 'tooltip' position, and delete the character from the input. There may be a way to invoke the tooltop itself, but I'm not aware of it.

      I know exactly where my computer is, so I have no idea how fast it's going.

      1 Reply Last reply
      0
      • K Offline
        K Offline
        Keozon
        wrote on 15 May 2012, 01:40 last edited by
        #3

        To give an example (I just test it)

        Assuming your QLineEdit widget is named 'username' and you use the default name for the slot to handle the signal,

        @
        void MyClass::on_username_textEdited(const QString &arg1){
        QString temp = arg1; /because arg1 is const/
        qDebug() << "Character input: " + temp.remove(0,arg1.length()-1);
        }@

        This outputs the individual character just input to the debug console. You could also use a QVerify instance to verify validity. How you implement the actual 'tooltip' is up to you. It could just be a QLabel that shows up above the field, and clears out on a QTimer::singleShot().

        I know exactly where my computer is, so I have no idea how fast it's going.

        1 Reply Last reply
        0
        • L Offline
          L Offline
          lgeyer
          wrote on 15 May 2012, 06:11 last edited by
          #4

          @
          QLineEdit *lineEdit = new QLineEdit;
          lineEdit->setValidator(new QRegExpValidator(QRegExp(...)));

          connect(lineEdit, SIGNAL(textEdited(QString)), this, SLOT(lineEditTextEdited()));

          void lineEditTextEdited()
          {
          if(lineEdit->hasAcceptableInput() == false)
          {
          QToolTip::showText(lineEdit->mapToGlobal(QPoint()), tr("Invalid Input"));
          }
          else
          {
          QToolTip::hideText();
          }
          }
          @

          1 Reply Last reply
          0
          • J Offline
            J Offline
            jaydeep17
            wrote on 15 May 2012, 09:17 last edited by
            #5

            @Lukas Geyer
            I tried your code..
            the validator works fine, it doesn't allow to input any invalid text, but the tooltip is not shown on invalid input..

            1 Reply Last reply
            0
            • K Offline
              K Offline
              Keozon
              wrote on 15 May 2012, 15:46 last edited by
              #6

              That's because textEdited isn't emitted if the input is invalid - the text doesn't actually change, and thus is not edited. So, its ALWAYS going to execute the 'else' condition. I could be wrong about that, depending on the implementation of setValidator, but you could check it with qDebug():

              @
              void lineEditTextEdited()
              {
              qDebug() << "Character entered!";
              if(lineEdit->hasAcceptableInput() == false)
              {
              QToolTip::showText(lineEdit->mapToGlobal(QPoint()), tr("Invalid Input"));
              }
              else
              {
              QToolTip::hideText();
              }

              }@

              Just add the qDebug line, and watch the output when you enter an invalid character. If it outputs the string while typing an invalid character, than I'm wrong.

              I really think you'll have to manually check each character entered against a validator yourself, without the setValidator method.

              Also, in order to properly handle cut/paste operations that change the text by whole strings instead of just one character at a time, you'll have to use a 'last value' variable to see if more than one character was added.

              Edit: I tested it myself, and textEdited is not emitted when an invalid character is input.

              So, I did it my way, and it works. You could then just use the tooltop code provided by Lukas to get what you want accomplished (assuming the tooltip function works - I did not test it).

              @void on_username_textEdited(const QString &arg1)
              {
              int length = arg1.length() -1;
              QString temp = arg1;
              QString inchar = temp.remove(0,length);
              QRegExpValidator validate(QRegExp("([a-z]|[A-Z])"));
              int pos = 1;
              if (validate.validate(inchar, pos) == QValidator::Acceptable){
              qDebug() << "Valid Character input: " + inchar;
              }
              else {
              qDebug() << "Invalid character input: " + inchar;
              temp = arg1;
              ui->username->setText(temp.remove(-1,1));
              }
              }
              @
              So, this example creates a new instance of QValidator on the stack with every single edit, but its not hard to change it to a persistent object on the heap, this is just simpler to write and read.

              I know exactly where my computer is, so I have no idea how fast it's going.

              1 Reply Last reply
              0
              • J Offline
                J Offline
                jaydeep17
                wrote on 15 May 2012, 18:25 last edited by
                #7

                :@Keozon
                I tried it, & I appreciate it, good work..
                but it's not that effective..

                ya obviously it works for your case but it doesn't for my case..
                It works somewhat strange..
                try replacing, line no. 6 in you code with.

                @QRegExpValidator validate(QRegExp("([a-zA-Z0-9]+ ?)*"));@

                this regex doesn't allow more than one white space between two words..

                1 Reply Last reply
                0
                • K Offline
                  K Offline
                  Keozon
                  wrote on 15 May 2012, 18:45 last edited by
                  #8

                  Okay; if you need to not only validate individual characters but also the string as a whole, add another QValidator with the "string regex" (or use one that works for both character and string validation), and check the arg1 value as a whole with each change. Change the if () condition to have an && to make sure the string as a whole is also valid. Should work how you want.

                  Edit: actually, you can probably skip validating the individual character and just validate the string as a whole, since if the string is valid, the character obviously is. So, just validate arg1 instead of inchar. Note that with string validation, you'll have to allow QVerify::Intermediate to qualify as valid, as well.

                  Tested, it works:
                  @
                  void on_username_textEdited(const QString &arg1)
                  {
                  int length = arg1.length() -1;
                  QString temp = arg1;
                  QString inchar = temp.remove(0,length);
                  QRegExpValidator validate(QRegExp("([a-zA-Z0-9]+ ?)*"));
                  int pos = arg1.length();
                  temp = arg1;
                  if (validate.validate(temp, pos) == QValidator::Acceptable){
                  debug("Valid character input: "+inchar);
                  }
                  else {
                  debug("Invalid character input :"+inchar);
                  ui->username->setText(temp.remove(-1,1));
                  }
                  }
                  @

                  Note that debug() is a method I defined previously.

                  I know exactly where my computer is, so I have no idea how fast it's going.

                  1 Reply Last reply
                  0
                  • L Offline
                    L Offline
                    lgeyer
                    wrote on 15 May 2012, 19:31 last edited by
                    #9

                    [quote author="jaydeep17" date="1337073440"]I tried your code.. the validator works fine, it doesn't allow to input any invalid text, but the tooltip is not shown on invalid input..[/quote]
                    You cannot enter invalid input if a validator is set, only intermediate (tooltip is shown) and acceptable.

                    If you want the user to be able to actually enter invalid input as well you should not use setValidator() (as suggested by Keozon) but use the validator to validate the text manually.
                    @
                    QRegExpValidator lineEditValidator_ = new QRegExpValidator(QRegExp("([a-zA-Z0-9]+ ?)"));

                    void lineEditTextEdited(const QString &text)
                    {
                    QString validatorText = text;
                    int validatorPosition = 0;
                    if(lineEditValidator_->validate(validatorText, validatorPosition) == QValidator::Invalid)
                    {
                    QToolTip::showText(lineEdit_->mapToGlobal(QPoint()), tr("Invalid Input"));
                    }
                    else
                    {
                    QToolTip::hideText();
                    }
                    }
                    @

                    1 Reply Last reply
                    0
                    • K Offline
                      K Offline
                      Keozon
                      wrote on 15 May 2012, 19:32 last edited by
                      #10

                      If you want to fix the 'copy and paste' problem, this is one (probably not the best) way of fixing it.
                      Let me know if it doesn't make sense.
                      @
                      void on_username_textEdited(const QString &arg1)
                      {
                      int length = arg1.length() -1;
                      QString temp = arg1;
                      QString inchar = temp.remove(0,length);
                      QRegExpValidator validate(QRegExp("[a-zA-Z]+([a-zA-Z0-9])*"));
                      int pos = arg1.length();
                      temp = arg1;
                      if (validate.validate(temp, pos) == QValidator::Acceptable){
                      debug("Valid character input: "+inchar);
                      }
                      else {
                      debug("Invalid character input :"+inchar);
                      ui->username->setText(temp.remove(-1,1));
                      /Make sure the string still is valid; i.e, no more than one character was input at once./
                      temp = ui->username->text();
                      pos = temp.length();
                      while (validate.validate(temp, pos) == QValidator::Invalid){
                      ui->username->setText(temp.remove(-1,1));
                      temp = ui->username->text();
                      pos = temp.length();
                      }
                      }
                      }
                      @

                      Edit:
                      @Lukas, I believe he does not want invalid input to be shown (my example eliminates all invalid input), but doesn't want the user to be sitting there, scratching their head in confusion as to why the field is not updating. So, he wants the tool tip to show when they try. The issue was getting the tooltip to show on invalid input while still not allowing that input to show.

                      I know exactly where my computer is, so I have no idea how fast it's going.

                      1 Reply Last reply
                      0
                      • J Offline
                        J Offline
                        jaydeep17
                        wrote on 15 May 2012, 20:30 last edited by
                        #11

                        @Lukas,
                        yes, Keozon is correct, I want to implement the same thing...

                        @Keozon
                        you know, the code that you posted in the last two comments, do the exact same thing, except that I had to change the regex...
                        but (no need to worry)
                        I got what I wanted..

                        Thanks for the help.. :)

                        1 Reply Last reply
                        0
                        • K Offline
                          K Offline
                          Keozon
                          wrote on 15 May 2012, 21:12 last edited by
                          #12

                          The last code segment I included handles "paste" into the field. The prior code segment only handles one character at a time. So, if a user were to type "name lastname" and then paste it in, the prior code would allow it, the second will not.

                          I know exactly where my computer is, so I have no idea how fast it's going.

                          1 Reply Last reply
                          0
                          • J Offline
                            J Offline
                            jaydeep17
                            wrote on 15 May 2012, 22:22 last edited by
                            #13

                            oh !!! :D
                            sorry, I didn't notice that...

                            1 Reply Last reply
                            0
                            • L Offline
                              L Offline
                              lgeyer
                              wrote on 16 May 2012, 06:52 last edited by
                              #14

                              [quote author="Keozon" date="1337110320"]I believe he does not want invalid input to be shown, but doesn’t want the user to be sitting there, scratching their head in confusion as to why the field is not updating. So, he wants the tool tip to show when they try. The issue was getting the tooltip to show on invalid input while still not allowing that input to show.[/quote]
                              I think he's got it ;-)

                              Just add a persistent state then, which reset the text on invalid input.
                              @
                              void lineEditTextEdited(const QString &text)
                              {
                              static QString lineEditValidText = lineEdit_->text();

                              QString validatorText = text;
                              int validatorPosition = 0;
                              if(lineEditValidator_->validate(validatorText, 
                                                              validatorPosition) == QValidator::Invalid)
                              {
                                 lineEdit_->setText(lineEditValidText);
                                 QToolTip::showText(lineEdit_->mapToGlobal(QPoint()), tr("Invalid Input"));
                              }
                              else
                              {
                                  lineEditValidText = lineEdit_->text();
                                  QToolTip::hideText();
                              }
                              

                              }
                              @
                              This is a perfect opportunity to refactor your code, as the implementation is currently limited to a single widget (which means duplicating the code for multiple widgets). One possibility is to use the charm pattern.
                              @
                              class ValidationCharm : public QObject
                              {
                              Q_OBJECT

                              public:
                              ValidationCharm(QObject *parent = 0) : QObject(parent) {}

                              void activateOn(QLineEdit *lineEdit, QValidator *validator)
                              {
                                  lineEdit->setProperty("previousText", 
                                                        QVariant::fromValue<QString>(lineEdit->text()));
                                  lineEdit->setProperty("validator", 
                                                        QVariant::fromValue<QValidator*>(validator));
                                  connect(lineEdit, SIGNAL(textEdited(QString)), this, SLOT(textEdited_(QString)));
                              }
                              
                              void deactivateOn(QLineEdit *lineEdit)
                              {
                                  disconnect(lineEdit, SIGNAL(textEdited(QString)), 
                                             this, SLOT(textEdited_(QString)));
                                  lineEdit->setProperty("previousText", QVariant());
                                  lineEdit->setProperty("validator", QVariant());
                              }
                              

                              private slots:
                              void textEdited_(const QString &text)
                              {
                              QLineEdit lineEdit = qobject_cast<QLineEdit>(sender());

                                  QValidator *validator = lineEdit->property("validator").value<QValidator*>();
                                  QString validatorText = text;
                                  int validatorPosition = 0;
                                  if(validator->validate(validatorText, 
                                                         validatorPosition) == QValidator::Invalid)
                                  {
                                      lineEdit->setText(lineEdit->property("previousText").value<QString>());
                                      QToolTip::showText(lineEdit->mapToGlobal(QPoint()), tr("Invalid Input"));
                                  }
                                  else
                                  {
                                      lineEdit->setProperty("previousText", 
                                                            QVariant::fromValue<QString>(lineEdit->text()));
                                      QToolTip::hideText();
                                  }
                              }
                              

                              };

                              Q_DECLARE_METATYPE(QValidator*)

                              ...

                              QValidator validator = new QRegExpValidator(QRegExp("([a-zA-Z0-9]+ +)"));
                              ValidationCharm *validatonCharm = new ValidationCharm;

                              validatonCharm->activateOn(lineEditA, validator);
                              validatonCharm->activateOn(lineEditB, validator);
                              validatonCharm->activateOn(lineEditC, validator);
                              @

                              [quote author="jaydeep17" date="1337106343"]
                              <code>QRegExpValidator validate(QRegExp("([a-zA-Z0-9]+ ?)"))</code> doesn't allow more than one white space between two words.
                              [/quote]
                              Yes, because according to the regular expression multiple whitespaces are invalid (? quantifier means zero or one). If you want to allow mutliple whitespaces use the + quantifier instead <code>QRegExp("([a-zA-Z0-9]+ +)
                              ")</code>.

                              1 Reply Last reply
                              0
                              • J Offline
                                J Offline
                                jaydeep17
                                wrote on 16 May 2012, 08:49 last edited by
                                #15

                                @Lukas Geyer
                                As i'm new to Opensource, I want to start some contribution, is it a good idea, if I make a patch for this tooltip concept and submit it to Qt ??

                                I have also decided, that I'll not only limit this to tooltips, I'll allow the developer to decide if he wants a tooltip to be shown or an errorbox..

                                Please give your views, on it..

                                1 Reply Last reply
                                0
                                • L Offline
                                  L Offline
                                  lgeyer
                                  wrote on 16 May 2012, 14:16 last edited by
                                  #16

                                  "Contributing":http://qt-project.org/contribute is always a good idea! ;-)

                                  However, contributions have to follow the "contribution guidelines":http://qt-project.org/wiki/Qt-Contribution-Guidelines, both style-wise and design-wise, so make sure you've got in touch with the "maintainer":http://qt-project.org/wiki/Maintainers or the developer community ("IRC":irc://irc.freenode.net/qt-labs, "mailing list":http://lists.qt-project.org/mailman/listinfo) to discuss if such functionality is most likely to be accepted and how it is implemented the most beneficial way before starting any work.

                                  I personally think that having an option to provide visual feedback on failed validation is quite a good thing. This can be as easy as adding a textRejected() signal to input widgets supporting validation, but this is an implementation detail.

                                  1 Reply Last reply
                                  0

                                  5/16

                                  15 May 2012, 09:17

                                  topic:navigator.unread, 11
                                  • Login

                                  • Login or register to search.
                                  5 out of 16
                                  • First post
                                    5/16
                                    Last post
                                  0
                                  • Categories
                                  • Recent
                                  • Tags
                                  • Popular
                                  • Users
                                  • Groups
                                  • Search
                                  • Get Qt Extensions
                                  • Unsolved