Qt - Edit button text on right click

I want to create a button that when the user right clicks on the button, a context menu comes up giving the user the option to replace the text on the button. When the user chooses the replace option, they can edit the text label on the button itself.

I've got the right click to create the context menu, and I can intercept the key events to change the label, but when I do this, I've got to deal with all the various keyboard functions, like deleting, for myself.

I'm wondering if there is a better way to do this. Is there a way that I can put a QLineEdit on a button to edit the button text?

This is the code that I've started.

EventButton::EventButton(QWidget *parent) : 
    QPushButton(parent) 
{ }

void EventButton::mousePressEvent(QMouseEvent *e) {
    if (e->button() == Qt::RightButton) {
        QMenu contextMenu;
        contextMenu.addAction("Replace Text", this, [=] {
            this->grabKeyboard();
            this->setText("");
        });

        QPoint globalPos = mapToGlobal(e->pos());
        contextMenu.exec(globalPos);
    } else {
        emit clicked();
    }
}

void EventButton::keyPressEvent(QKeyEvent *e) {
    // Check for return key
    if ((e->key() == Qt::Key_Enter) || (e->key() == Qt::Key_Return)) {
         this->releaseKeyboard();
         emit buttonTitleChanged(this->text());
    } else {
         QString text = this->text();
         text.append(e->key());
         this->setText(text);
    }
}

2 answers

  • answered 2018-05-16 06:42 Jiu

    Is there a way that I can put a QLineEdit on a button to edit the button text?

    Just put it on and only show it when you need text editing.

    class EditButton : public QPushButton
    {
    public:
        explicit EditButton(const QString &text, QWidget *parent = Q_NULLPTR) :
            QPushButton(text, parent),
            mLineEdit(new QLineEdit(text, this))
        {
            mLineEdit->hide();
            connect(mLineEdit, &QLineEdit::editingFinished, [=](){
                setText(mLineEdit->text());
                mLineEdit->hide();
            });
            connect(this, &EditButton::clicked, [=](){
                qDebug()<<"Left clicked"; // Right click only for text edit
            });
        }
        ~EditButton()
        {
            mLineEdit->deleteLater();
        }
    
    protected:
        void resizeEvent(QResizeEvent *event) override {
            Q_UNUSED(event)
            mLineEdit->resize(contentsRect().size());
        }
        void mouseReleaseEvent(QMouseEvent *e) override {
            if(e->button() == Qt::RightButton) {
                mLineEdit->setText(text());
                mLineEdit->show();
            } else
                QPushButton::mouseReleaseEvent(e);
        }
    private:
        QLineEdit* mLineEdit;
    };
    

  • answered 2018-05-16 14:29 p-a-o-l-o

    You can just add a QLineEdit child to the button. I would also give the button a grid layout to automatically handle the line edit positioning and resizing and override contextMenuEvent to show the menu, to end up with something like this:

    #include <QPushButton>
    #include <QMenu>
    #include <QAction>
    #include <QContextMenuEvent>
    #include <QGridLayout>
    class EventButton : public QPushButton
    {
        Q_OBJECT
        QLineEdit * lineEdit;
    public:
        explicit EventButton(const QString &text, QWidget *parent) :
            QPushButton(text, parent)
        {
            lineEdit = new QLineEdit();
            lineEdit->setAlignment(Qt::AlignCenter | Qt::AlignHCenter);
            lineEdit->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
            connect(lineEdit, &QLineEdit::editingFinished, [=](){
                        setText(lineEdit->text());
                        lineEdit->hide();
                    });
    
            QGridLayout * gridlayout = new QGridLayout();
            gridlayout->setMargin(0);
            setLayout(gridlayout);
            gridlayout->addWidget(lineEdit);
            lineEdit->hide();
        }
    protected:
        void contextMenuEvent(QContextMenuEvent *event) override
        {
            QMenu contextMenu;
            contextMenu.addAction("Replace Text", this, [=] {
                QString text = this->text();
                lineEdit->setText(text);
                lineEdit->setSelection(0, text.size());
                lineEdit->show();
                lineEdit->setFocus();
            });
    
            QPoint globalPos = mapToGlobal(event->pos());
            contextMenu.exec(globalPos);
        }
    };