Display only the last character in a QLineEdit for a few seconds

90 Views Asked by At

QLineEdit offers 4 EchoMode states.

When typing a password, QLineEdit::Password is suitable because it displays a circle (or something similar) instead of the typed characters.

What I want to do is to hide all characters, like with QLineEdit::Password, but the last typed character is visible for a few seconds before it is replaced by a circle. This allows the user to check that they are using their password correctly.

1

There are 1 best solutions below

0
Pamputt On BEST ANSWER

Here is my solution. The last character is hidden after 500 milliseconds.

lineeditvanishingcharacters.cpp

#include "lineeditvanishingcharacters.h"

#include <QTextLayout>
#include <QPainter>

LineEditVanishingCharacters::LineEditVanishingCharacters(QWidget *parent)
    : QLineEdit(parent)
    , m_is_new_character(false)
{
    setEchoMode(QLineEdit::Password);

    connect(this, &LineEditVanishingCharacters::textEdited,
            this, &LineEditVanishingCharacters::textHasBeenEdited);

    m_timer = new QTimer(this);
    connect(m_timer, &QTimer::timeout, this, [this]() {
        update();
        m_is_new_character = false;
    });
    m_timer->start(500); // 0.5 second
}

void LineEditVanishingCharacters::textHasBeenEdited()
{
    m_is_new_character = true;
    m_timer->start();
}

void LineEditVanishingCharacters::paintEvent(QPaintEvent *event)
{
    // first paint as the default QLineEdit all characters but the last one
    if(text().isEmpty()) {
        QLineEdit::paintEvent(event);
        return;
    }

    // no new character has been typed, then hide the full text
    if(!m_is_new_character) {
        QLineEdit::paintEvent(event);
        return;
    }

    // if not focused anymore
    // then hide all characters
    if(!hasFocus()) {
        QLineEdit::paintEvent(event);
        return;
    }

    const QString first_characters = text().chopped(1);
    const QString last_character = text().last(1);
    setText(first_characters);

    QLineEdit::paintEvent(event);

    // restore the full text
    setText(first_characters+last_character);

    // ensure font() is up to date
    ensurePolished();

    // then, draw the last character
    // &. compute the cursor position
    const QRect cr = cursorRect();
    const QPoint pos = cr.topRight() - QPoint(cr.width(), 0.);

    // create the QTextLayout and add the last character to it
    QTextLayout l(last_character, font());
    l.beginLayout();
    QTextLine line = l.createLine();
    line.setLineWidth(width() - pos.x());
    line.setPosition(pos);
    l.endLayout();

    QPainter p(this);
    // set text color to match the textedit text color
    p.setPen(palette().text().color());
    l.draw(&p, QPoint(0, 0));
}

lineeditvanishingcharacters.h

#ifndef LINEEDITVANISHINGCHARACTERS_H
#define LINEEDITVANISHINGCHARACTERS_H

#include <QLineEdit>
#include <QPaintEvent>

class LineEditVanishingCharacters : public QLineEdit
{
    Q_OBJECT

public:
    LineEditVanishingCharacters(QWidget *parent = nullptr);

public Q_SLOTS:
    void textHasBeenEdited();

protected:
    void paintEvent(QPaintEvent *event);

private:
    bool m_is_new_character;
};

#endif // LINEEDITVANISHINGCHARACTERS_H