5

I want a QLineEdit not to display the entered text, but a processed version, while keeping the original text and returning it when it's requested via text(). Like with the password echo mode, but I don't want each character to be masked. I want to viasualize spaces:

E. g. when some text with spaces in between is entered, some·text·with·spaces·in·between should be shown so that one can see the spaces. Just like when e. g. you activate that ¶ symbol in LibreOffice.

There's QLineEdit::displayText(), but it can't be set, only read. Also, the echoMode can only be set via an enum, and with EchoMode::Password set, the processing seems to happen in private functions of QLineEdit, so that I also can't override some processing function.

Is this possible?

Dimitry Ernot
  • 6,256
  • 2
  • 25
  • 37
Tobias Leupold
  • 1,512
  • 1
  • 16
  • 41

2 Answers2

2

IMHO, it will be hard to do that with a QLineEdit.

But, it's quite easy with a QTextEdit by configuring its QTextDocument:

class TextEdit : public QTextEdit
{
    Q_OBJECT
public:
        explicit TextEdit(QWidget* parent=nullptr): QTextEdit (parent)
        {
                QTextDocument* doc = new QTextDocument(this);
                setDocument(doc);
                QTextOption option;
                option.setFlags(QTextOption::ShowLineAndParagraphSeparators | QTextOption::ShowTabsAndSpaces);
                doc->setDefaultTextOption(option);
        }
};

Then, you have to configure the TextEdit to get the same behavior than a QLineEdit (i.e. one line, no scrollbar, etc.).

A quick example as a good start:

class OneLineTextEdit : public QTextEdit
{
    Q_OBJECT
public:
        explicit OneLineTextEdit(QWidget* parent=nullptr): QTextEdit (parent)
        {
                setTabChangesFocus(true);
                setWordWrapMode(QTextOption::NoWrap);
                // No scrollbars
                setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
                setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
                setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);

                // One line only
                setFixedHeight(sizeHint().height());

                // Show the space/tabs/return
                QTextDocument* doc = new QTextDocument(this);
                setDocument(doc);
                QTextOption option;
                option.setFlags(QTextOption::ShowLineAndParagraphSeparators | QTextOption::ShowTabsAndSpaces);
                doc->setDefaultTextOption(option);
        }

    // We don't want to write more than one line
    void keyPressEvent(QKeyEvent *event)
    {
        if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)
                return event->ignore();
        return QTextEdit::keyPressEvent(event);
    }

    // Don't display more than one line
    QSize sizeHint() const
    {
        QFontMetrics const fm(font());
        int const h = qMax(fm.height(), 14) + 4;
        int const w = fm.width(QLatin1Char('x')) * 17 + 4;
        QStyleOption opt;
        opt.initFrom(this);
        // Use the current app style to find the size of a real QLineEdit
        return (style()->sizeFromContents(QStyle::CT_LineEdit, &opt, QSize(w, h).
                expandedTo(QApplication::globalStrut()), this));
    }
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    OneLineTextEdit *editor = new OneLineTextEdit();
    editor->show();

    return app.exec();
};
Dimitry Ernot
  • 6,256
  • 2
  • 25
  • 37
0

Here's what finally did:

SpacesLineEdit.h:

#include <QPlainTextEdit>

class SpacesLineEdit : public QPlainTextEdit
{
    Q_OBJECT

public:
    explicit SpacesLineEdit(QWidget *parent = nullptr);
    void setText(const QString &text);
    QString text() const;

protected:
    virtual void keyPressEvent(QKeyEvent *event) override;
    virtual QSize sizeHint() const override;
    virtual QSize minimumSizeHint() const override;
    virtual void insertFromMimeData(const QMimeData *source) override;

private: // Variables
    QSize m_sizeHint;

};

SpacesLineEdit.cpp:

#include "SpacesLineEdit.h"
#include <QLineEdit>
#include <QMimeData>

SpacesLineEdit::SpacesLineEdit(QWidget *parent) : QPlainTextEdit(parent)
{
    setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    setLineWrapMode(QPlainTextEdit::NoWrap);
    setTabChangesFocus(true);

    QTextOption option = document()->defaultTextOption();
    option.setFlags(option.flags() | QTextOption::ShowTabsAndSpaces);
    document()->setDefaultTextOption(option);

    // Stealing the sizeHint from a plain QLineEdit will do for now :-P
    QLineEdit lineEdit;
    m_sizeHint = lineEdit.sizeHint();
}

QSize SpacesLineEdit::minimumSizeHint() const
{
    return m_sizeHint;
}

QSize SpacesLineEdit::sizeHint() const
{
    return m_sizeHint;
}

void SpacesLineEdit::keyPressEvent(QKeyEvent *event)
{
    if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) {
        event->ignore();
        return;
    }
    QPlainTextEdit::keyPressEvent(event);
}

void SpacesLineEdit::insertFromMimeData(const QMimeData *source)
{
    QString text = source->text();
    text.replace(QLatin1String("\r\n"), QLatin1String(" "));
    text.replace(QLatin1Char('\n'), QLatin1String(" "));
    text.replace(QLatin1Char('\r'), QLatin1String(" "));

    QMimeData processedSource;
    processedSource.setText(text);
    QPlainTextEdit::insertFromMimeData(&processedSource);
}

void SpacesLineEdit::setText(const QString &text)
{
    setPlainText(text);
}

QString SpacesLineEdit::text() const
{
    return toPlainText();
}
Tobias Leupold
  • 1,512
  • 1
  • 16
  • 41