QLineEdit with custom button
Asked Answered
D

3

10

I need to implement LineEdit widget with possibility to add tool buttons at the right end of text area. I know two ways of doing that but both solutions seems ugly.

1) add tool buttons as child widgets of QLineEdit and handle resizeEvent to position them correctly. The main disadvantage is that if text is enough long it may appear under tool buttons.

2) Another solution is to put line edit and buttons inside frame and overwrite style to hide lineEdits frame and make QFrame look like QLineEdit.

I need a best way to implement such widget. Also my widget should be style aware.

Darrow answered 20/1, 2014 at 11:1 Comment(3)
You want to add more than one QToolButton in your QLineEdit?Dark
For now I have to add only one but in the future it may be two or moreDarrow
I posted my solution below. ResizeEvent is used there. Also you can style QLineEdit using QSS, so I think as starting point it'll be enough.Dark
B
5

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());
}
Brammer answered 20/1, 2014 at 11:5 Comment(2)
What is the use of these "link-and-run" answers??! The target page's links are all dead and this answer has become useless. Please don't just provide a link; explain the solution too. Links rot.Odontalgia
@ThePeacefulCoder Indeed. This is why link-only answers are bad. I pulled the link's content from the wayback machine and added the important parts to the post.Bourque
T
46

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

Tanguy answered 29/1, 2015 at 12:12 Comment(2)
This. Also there's convenience for the clear button (setClearButtonEnabled).Jingoism
I tried this implementation on PyQt5 and this worked! But the icon size isn't probably scalable!Nonce
B
5

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());
}
Brammer answered 20/1, 2014 at 11:5 Comment(2)
What is the use of these "link-and-run" answers??! The target page's links are all dead and this answer has become useless. Please don't just provide a link; explain the solution too. Links rot.Odontalgia
@ThePeacefulCoder Indeed. This is why link-only answers are bad. I pulled the link's content from the wayback machine and added the important parts to the post.Bourque
D
3

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.

Dark answered 20/1, 2014 at 12:55 Comment(1)
This approach worked for me in PyQt5!! ThanksNonce

© 2022 - 2024 — McMap. All rights reserved.