gnase
gnase

Reputation: 638

Reveal password for dialog in Qt

I need to create a login dialog like this

enter image description here enter image description here

image files: eyeOn.png, eyeOff.png

Requirements:

I have just built the layout.

QGridLayout *mainlogin = new QGridLayout();

QLabel *usernameLabel = new QLabel;
usernameLabel->setWordWrap(true);
usernameLabel->setText("Username");
mainlogin->addWidget(usernameLabel, 0, 0);

QComboBox *usernameLineEdit = new QComboBox;
usernameLineEdit->setEditable(true);
usernameLabel->setBuddy(usernameLineEdit);
mainlogin->addWidget(usernameLineEdit, 0, 1);

QLabel *capslockShow = new QLabel;
capslockShow->setWordWrap(true);
capslockShow->setText(" ");
mainlogin->addWidget(capslockShow, 1, 1);

QLabel *passwordLabel = new QLabel;
passwordLabel->setWordWrap(true);
passwordLabel->setText("Password");
mainlogin->addWidget(passwordLabel, 2, 0);
QLineEdit *passwordLineEdit = new QLineEdit;
passwordLineEdit->setEchoMode(QLineEdit::Password);
QAction *myAction = passwordLineEdit->addAction(QIcon(":/eyeOff.png"), QLineEdit::TrailingPosition);
passwordLabel->setBuddy(passwordLineEdit);
mainlogin->addWidget(passwordLineEdit, 2, 1);

What should I do next? Pls help me with code snippet.

Upvotes: 3

Views: 3445

Answers (2)

eyllanesc
eyllanesc

Reputation: 243945

The solution is to add a QAction to the QLineEdit, this will create a QToolButton that we can obtain from the associatedWidgets() (it will be the second widget since the first one is the one associated with clearButton). Already having the QToolButton you must use the pressed and released signal.

passwordlineedit.h

#ifndef PASSWORDLINEEDIT_H
#define PASSWORDLINEEDIT_H

#include <QAction>
#include <QLineEdit>
#include <QToolButton>

class PasswordLineEdit: public QLineEdit
{
public:
    PasswordLineEdit(QWidget *parent=nullptr);
private slots:
    void onPressed();
    void onReleased();
protected:
    void enterEvent(QEvent *event);
    void leaveEvent(QEvent *event);
    void focusInEvent(QFocusEvent *event);
    void focusOutEvent(QFocusEvent *event);
private:
    QToolButton *button;
};

#endif // PASSWORDLINEEDIT_H

passwordlineedit.cpp

#include "passwordlineedit.h"

PasswordLineEdit::PasswordLineEdit(QWidget *parent):
    QLineEdit(parent)
{
    setEchoMode(QLineEdit::Password);
    QAction *action = addAction(QIcon(":/eyeOff"), QLineEdit::TrailingPosition);
    button = qobject_cast<QToolButton *>(action->associatedWidgets().last());
    button->hide();
    button->setCursor(QCursor(Qt::PointingHandCursor));
    connect(button, &QToolButton::pressed, this, &PasswordLineEdit::onPressed);
    connect(button, &QToolButton::released, this, &PasswordLineEdit::onReleased);
}

void PasswordLineEdit::onPressed(){
    QToolButton *button = qobject_cast<QToolButton *>(sender());
    button->setIcon(QIcon(":/eyeOn"));
    setEchoMode(QLineEdit::Normal);
}

void PasswordLineEdit::onReleased(){
    QToolButton *button = qobject_cast<QToolButton *>(sender());
    button->setIcon(QIcon(":/eyeOff"));
    setEchoMode(QLineEdit::Password);
}

void PasswordLineEdit::enterEvent(QEvent *event){
    button->show();
    QLineEdit::enterEvent(event);
}

void PasswordLineEdit::leaveEvent(QEvent *event){
    button->hide();
    QLineEdit::leaveEvent(event);
}

void PasswordLineEdit::focusInEvent(QFocusEvent *event){
    button->show();
    QLineEdit::focusInEvent(event);
}

void PasswordLineEdit::focusOutEvent(QFocusEvent *event){
    button->hide();
    QLineEdit::focusOutEvent(event);
}

The complete example can be downloaded from the following link.

Upvotes: 5

G.M.
G.M.

Reputation: 12879

Rather than trying to make use of the QAction returned by QLineEdit::addAction you could probably use a QWidgetAction for this when combined with a suitable event filter...

class eye_spy: public QWidgetAction {
  using super = QWidgetAction;
public:
  explicit eye_spy (QLineEdit *control, QWidget *parent = nullptr)
    : super(parent)
    , m_control(control)
    , m_on(":/eyeOn")
    , m_off(":/eyeOff")
    , m_pixmap_size(50, 50)
    {
      m_label.setScaledContents(true);
      m_control->setEchoMode(QLineEdit::Password);
      m_label.setPixmap(m_off.pixmap(m_pixmap_size));
      m_label.installEventFilter(this);
      setDefaultWidget(&m_label);
    }
protected:
  virtual bool eventFilter (QObject *obj, QEvent *event) override
    {
      if (event->type() == QEvent::MouseButtonPress) {
        m_control->setEchoMode(QLineEdit::Normal);
        m_label.setPixmap(m_on.pixmap(m_pixmap_size));
      } else if (event->type() == QEvent::MouseButtonRelease) {
        m_control->setEchoMode(QLineEdit::Password);
        m_label.setPixmap(m_off.pixmap(m_pixmap_size));
      }
      return(super::eventFilter(obj, event));
    }
private:
  QLineEdit *m_control;
  QLabel     m_label;
  QIcon      m_on;
  QIcon      m_off;
  QSize      m_pixmap_size;
};

Now, rather than...

QAction *myAction = passwordLineEdit->addAction(QIcon(":/eyeOff.png"), QLineEdit::TrailingPosition);

Use...

eye_spy eye_spy(passwordLineEdit);
passwordLineEdit->addAction(&eye_spy, QLineEdit::TrailingPosition);

Seems to provide the desired behaviour.

Upvotes: 3

Related Questions