实现思路

通过继承QPushButton,然后通过双击事件唤出QLineEdit进行编辑,在编辑焦点消失后把QLineEdit的文本给到QPushButton并隐藏QLineEdit输入框。

这种实现方式的关键点有两个,分别是使用QLineEditsetGeometry 方法使其与QPushButton 完全重合;另一个关键点是在QLineEdit 的编辑结束后将文本数据写回到QPushButton

完整代码见Github

演示效果如下
EditableButton.gif

实现的主要代码如下:

#include "EditableButton.h"
#include <QTimer>
#include <QDebug>


EditableButton::EditableButton(QWidget *parent) : QPushButton(parent),
    mEdit(nullptr)
{
    setText(tr("Edit Me!"));
    mEdit = new EditableButtonLineEdit(this->parentWidget());
    connect(mEdit, &QLineEdit::editingFinished,
            this, &EditableButton::onEditFinished, Qt::DirectConnection);
    mEdit->setText(text());
    mEdit->resize(this->width(), this->height());
    mEdit->setAlignment(Qt::AlignCenter);
    mEdit->setGeometry(this->geometry());
    mEdit->setContextMenuPolicy(Qt::NoContextMenu);
    mEdit->hide();
}

void EditableButton::createEditLabel()
{
    if (mEdit) {

        mEdit->setText(text());
        mEdit->setGeometry(this->geometry());
        mEdit->show();
        mEdit->setFocus(Qt::NoFocusReason);
        mEdit->selectAll();
        mEdit->setCursorPosition(mEdit->text().size());
    }
}

void EditableButton::destroyEditLabel()
{
    if (mEdit) {
        mEdit->hide();
    }
}

void EditableButton::onEditFinished()
{
    if (mEdit->isVisible()) {
        if (mEdit->text() != this->text()) {
            this->setText(mEdit->text());
            Q_EMIT textChanged(this->text());
        }
    }
    destroyEditLabel();
}

void EditableButton::mouseDoubleClickEvent(QMouseEvent *ev)
{
    QPushButton::mouseDoubleClickEvent(ev);
    createEditLabel();
}

/**
 * @brief EditableButton::focusOutEvent
 * @param ev
 *
 * Override the focusOutEvent to force edit finish.
 */
void EditableButton::focusOutEvent(QFocusEvent *ev)
{
    if (mEdit->isVisible()) {
        Q_EMIT mEdit->editingFinished();
    }
    destroyEditLabel();
}



EditableButtonLineEdit::EditableButtonLineEdit(QWidget *parent) : QLineEdit(parent)
{

}

/**
 * @brief EditableButtonLineEdit::focusOutEvent
 * @param ev
 *
 * Override the focusOutEvent to force edit finish.
 */
void EditableButtonLineEdit::focusOutEvent(QFocusEvent *ev)
{
    QLineEdit::focusOutEvent(ev);
    Q_EMIT editingFinished();
}