Kategoria: Qt

C++, Qt

Limited QTextEdit – do it the right way

Recently during development, I encountered a problem in adding a character limit to the QTextEdit element. I will describe the most frequently suggested solution, which is in my opinion wrong. And the other way, which was usually suggested by more experienced developers, but not presented in the code.

The wrong way

Usually, you can find the following solution, which is quite intuitive in Qt:

  1. Create textChanged event handler.
  2. Extract QTextEdit text, and check its length.
  3. Modify it the way you want and call textEdit->setText with modified text.
  4. Update QTextEdit cursor (carriage) position.

What is wrong with that solution? The problem is that calling setText in textChanged handler is a way to create endless recursion. Qt signals and slots are a nice way to decouple things, but unfortunately, some scenarios can lead you to problems.

Even if this way will work in your environment, it is strongly related to the Qt implementation. In my case, the program ends on Segmentation fault.

The right way

The right way, proposed by more advanced developers on the Qt forum looks like that:

  1. Create a new class, for example, LimitedTextEdit which derives from QTextEdit.
  2. Overload keyPressEvent and keyReleaseEvent methods. Their content should check if the text, extracted with toPlainText() matches the character limit. If it does, the base class method should be called (keyPressEvent or keyReleaseEvent), otherwise, it will filter out the pressed key.
  3. Promote your QTextEdit to LmitedTextEdit in Design editor.

Below you can find my implementation, limitedtextedit.h:

#ifndef LIMITEDTEXTEDIT_H
#define LIMITEDTEXTEDIT_H

#include <QTextEdit>

class LimitedTextEdit : public QTextEdit
{
public :
    LimitedTextEdit(QWidget *parent = 0) : QTextEdit(parent) { }
    virtual ~LimitedTextEdit() { }

protected :
    virtual void keyPressEvent(QKeyEvent *e) override;
    virtual void keyReleaseEvent(QKeyEvent *e) override;
};

#endif // LIMITEDTEXTEDIT_H

limitedtextedit.cpp:

#include "limitedtextedit.h"

#define LIMITED_TEXT_EDIT_MAX 120

void LimitedTextEdit::keyPressEvent(QKeyEvent *e)
{
    int len = QTextEdit::toPlainText().toAscii().length();
    if (len < LIMITED_TEXT_EDIT_MAX)
    {
        QTextEdit::keyPressEvent(e);
    }
}

void LimitedTextEdit::keyReleaseEvent(QKeyEvent *e)
{
    int len = QTextEdit::toPlainText().toAscii().length();
    if (len < LIMITED_TEXT_EDIT_MAX)
    {
        QTextEdit::keyReleaseEvent(e);
    }
}

This part is scalable. You may add parsing keys, passed to the event handler, and for example, unlock arrow keys or block pasting content, Everything here is in your hands. If you want to react on a key normally, just pass it to QTextEdit implementation. Now you have to promote your generated by a designer QTextEdit object:

After that just click Add and Promote.