1

I want to convert all lowercase characters as I type to uppercase in a QPlainTextEdit. In a QLineEdit I do the same via a validator, but there seems to be no validator for QPlainTextEdit.

I have tried ui->pte_Route->setInputMethodHints(Qt::ImhUppercaseOnly); but it does nothing, most likely using it wrong.

Any better option as using my "own" class?

Horst Walter
  • 13,663
  • 32
  • 126
  • 228

3 Answers3

1

A quick test using an event filter seems to work reasonably well...

class plain_text_edit: public QPlainTextEdit {
  using super = QPlainTextEdit;
public:
  explicit plain_text_edit (QWidget *parent = nullptr)
    : super(parent)
    {
      installEventFilter(this);
    }
protected:
  virtual bool eventFilter (QObject *obj, QEvent *event) override
    {
      if (event->type() == QEvent::KeyPress) {
        if (auto *e = dynamic_cast<QKeyEvent *>(event)) {

          /*
           * If QKeyEvent::text() returns an empty QString then let normal
           * processing proceed as it may be a control (e.g. cursor movement)
           * key.  Otherwise convert the text to upper case and insert it at
           * the current cursor position.
           */
          if (auto text = e->text(); !text.isEmpty()) {
            insertPlainText(text.toUpper());

            /*
             * return true to prevent further processing.
             */
            return true;
          }
        }
      }
      return super::eventFilter(obj, event);
    }

If it does work sufficiently well then the event filter code can always be pulled out separately for re-use.

G.M.
  • 12,232
  • 2
  • 15
  • 18
  • Note that it makes no sense to install event filters on *yourself*. Just override `keyPressEvent` or `event` or one of the event dispatchers -- you're the target of the event, after all. – peppe Apr 13 '19 at 11:36
1

Using event filters for such a simple task does not look like a good idea, since you are forced to implement either a separate class inheriting QPlainTextEdit or create some separate class working as a filter. Instead, you could also do the following:

// Note. This is just a sample. Assume that 'this' is context of some class (e.g. class implementing QDialog/QMainWindow)
auto lineEdit = new QLineEdit();
/*
Here, you can use also &QLineEdit::textChanged, and it would not cause any stackoverflow,
since Qt is pretty optimized here, i.e. if text does not change actually (value of QString
remains the same), Qt won't fire the signal. However, it is probably better to use
&QLineEdit::textEdited, since you expect the user to enter the text.
*/
connect(lineEdit, &QLineEdit::textEdited, this, [lineEdit](const QString& text)
{
    lineEdit->setText(text.toUpper());
});

In other words, you can achieve the same behavior desired through simple signals and slots mechanism that Qt gives us. If you can achieve what you want through standard framework mechanisms, then you should try this instead of trying to implement event filter which might cause problems you might even be unaware of. Keep in mind that event filter is another mechanism provided by Qt that gives you more freedom to do what you want to do, but also you have to take of much more corner cases.

1

I got a problem with eventFilter method and I used a simpler solution:

protected:
    void keyPressEvent(QKeyEvent* e) override {
        if (!e->text().isNull() && !e->text().isEmpty() &&
            e->modifiers() == Qt::NoModifier &&
            e->key() >= Qt::Key_A && e->key() <= Qt::Key_Z)
        {
            insertPlainText(e->text().toUpper());
        }
        else
            QPlainTextEdit::keyPressEvent(e);
    }

I am using CodeEditor class from Qt examples which inherits from QPlainTextEdit.

Papayaved
  • 103
  • 1
  • 1
  • 11