QLineEdit with custom button

As of Qt 5.2 one can use QLineEdit::addAction(...) to insert custom buttons. (Qt Docs)

Example (assume we're inside the definition of MyClass):

QLineEdit *myLineEdit = new QLineEdit(this);
QAction *myAction = myLineEdit->addAction(QIcon("test.png"), QLineEdit::TrailingPosition);
connect(myAction, &QAction::triggered, this, &MyClass::onActionTriggered);

enter image description here


The original blog post is gone now, but Trolltech once posted an example of a clear button for Qt 4.

Results

Line edit with no text:

Line edit with some text (button appears):

Line edit full of text (doesn’t go underneath button):

Source

lineedit.h

/****************************************************************************
**
** Copyright (c) 2007 Trolltech ASA <[email protected]>
**
** Use, modification and distribution is allowed without limitation,
** warranty, liability or support of any kind.
**        
****************************************************************************/

#ifndef LINEEDIT_H
#define LINEEDIT_H

#include <QLineEdit>

class QToolButton;

class LineEdit : public QLineEdit
{
    Q_OBJECT

public:
    LineEdit(QWidget *parent = 0);

protected:
    void resizeEvent(QResizeEvent *);

private slots:
    void updateCloseButton(const QString &text);

private:
    QToolButton *clearButton;
};

#endif // LIENEDIT_H

lineedit.cpp

/****************************************************************************
**
** Copyright (c) 2007 Trolltech ASA <[email protected]>
**
** Use, modification and distribution is allowed without limitation,
** warranty, liability or support of any kind.
**
****************************************************************************/

#include "lineedit.h"
#include <QToolButton>
#include <QStyle>

LineEdit::LineEdit(QWidget *parent)
    : QLineEdit(parent)
{
    clearButton = new QToolButton(this);
    QPixmap pixmap("fileclose.png");
    clearButton->setIcon(QIcon(pixmap));
    clearButton->setIconSize(pixmap.size());
    clearButton->setCursor(Qt::ArrowCursor);
    clearButton->setStyleSheet("QToolButton { border: none; padding: 0px; }");
    clearButton->hide();
    connect(clearButton, SIGNAL(clicked()), this, SLOT(clear()));
    connect(this, SIGNAL(textChanged(const QString&)), this, SLOT(updateCloseButton(const QString&)));
    int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
    setStyleSheet(QString("QLineEdit { padding-right: %1px; } ").arg(clearButton->sizeHint().width() + frameWidth + 1));
    QSize msz = minimumSizeHint();
    setMinimumSize(qMax(msz.width(), clearButton->sizeHint().height() + frameWidth * 2 + 2),
                   qMax(msz.height(), clearButton->sizeHint().height() + frameWidth * 2 + 2));
}

void LineEdit::resizeEvent(QResizeEvent *)
{
    QSize sz = clearButton->sizeHint();
    int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
    clearButton->move(rect().right() - frameWidth - sz.width(),
                      (rect().bottom() + 1 - sz.height())/2);
}

void LineEdit::updateCloseButton(const QString& text)
{
    clearButton->setVisible(!text.isEmpty());
}

Once I implemented such solution for this:

// LineEdit.h

#ifndef LINEEDIT_H
#define LINEEDIT_H

#include <QLineEdit>

class QToolButton;

class LineEdit : public QLineEdit
{
    Q_OBJECT

public:
    LineEdit(QWidget *parent = 0);

protected:
    void resizeEvent(QResizeEvent *);

private:
    QToolButton *furfurIcon;
};

#endif // LINEEDIT_H

// LineEdit.cpp

#include "lineedit.h"
#include <QToolButton>
#include <QStyle>

LineEdit::LineEdit(QWidget *parent)
    : QLineEdit(parent)
{
    furfurIcon = new QToolButton(this);

    QPixmap pixmap(":/root/your_icon");
    furfurIcon->setIcon(QIcon(pixmap));
    furfurIcon->setIconSize(pixmap.size());
    furfurIcon->setCursor(Qt::ArrowCursor);
    furfurIcon->setStyleSheet("QToolButton
                              "{"
                              "border: none; padding: 0px;"
                              "}");

    setStyleSheet(QString("QLineEdit"
                          "{"
                          "border: 1px solid;"
                          "border-color: rgb(148, 168, 199);"
                          "border-radius: 10px;"
                          "background: white;"
                          "padding-left: %1px;"
                          "}").arg(furfurIcon->sizeHint().width() - 4));

    setMinimumSize(0, 25);
}

void LineEdit::resizeEvent(QResizeEvent *)
{
    QSize sz = furfurIcon->sizeHint();
    furfurIcon->move(rect().left(), (rect().bottom() + 1 - sz.height()) / 2);
}

Position of QToolButton is handled in resizeEvent. If there are more than one you'll have to adjust their coordinates. Also you can modify it to use layout. There is no text overlapping here.