I want a widget in Qt that will act like a spreadsheet cell does. It can display text, then when the user double-clicks on it, it becomes editable. Once the user is done with editing and presses Enter, the text gets saved and the control is not editable anymore. If the user hits Escape while editing, then the control returns to its previous value.
One possible solution is sub-classing QWidget
, QLabel
and QLineEdit
. Are there any other solutions available in Qt?
The following version also implements the same functionalities of your answer but instead of subclassing the QLineEdit
and the QLabel
only use eventFilter()
and instead of managing the visibility manually let QStackedWidget
do it.
#include <QApplication>
#include <QFormLayout>
#include <QKeyEvent>
#include <QLabel>
#include <QLineEdit>
#include <QStackedWidget>
#include <QVBoxLayout>
class MyEditableLabel: public QWidget{
Q_OBJECT
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
public:
MyEditableLabel(QWidget *parent=nullptr):
QWidget(parent),
mLabel(new QLabel),
mLineEdit(new QLineEdit)
{
setLayout(new QVBoxLayout);
layout()->setMargin(0);
layout()->setSpacing(0);
layout()->addWidget(&stacked);
stacked.addWidget(mLabel);
stacked.addWidget(mLineEdit);
mLabel->installEventFilter(this);
mLineEdit->installEventFilter(this);
setSizePolicy(mLineEdit->sizePolicy());
connect(mLineEdit, &QLineEdit::textChanged, this, &MyEditableLabel::setText);
}
bool eventFilter(QObject *watched, QEvent *event){
if (watched == mLineEdit) {
if(event->type() == QEvent::KeyPress){
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if(keyEvent->key() == Qt::Key_Return ||
keyEvent->key() == Qt::Key_Escape ||
keyEvent->key() == Qt::Key_Enter)
{
mLabel->setText(mLineEdit->text());
stacked.setCurrentIndex(0);
}
}
else if (event->type() == QEvent::FocusOut) {
mLabel->setText(mLineEdit->text());
stacked.setCurrentIndex(0);
}
}
else if (watched == mLabel) {
if(event->type() == QEvent::MouseButtonDblClick){
stacked.setCurrentIndex(1);
mLineEdit->setText(mLabel->text());
mLineEdit->setFocus();
}
}
return QWidget::eventFilter(watched, event);
}
QString text() const{
return mText;
}
void setText(const QString &text){
if(text == mText)
return;
mText == text;
emit textChanged(mText);
}
signals:
void textChanged(const QString & text);
private:
QLabel *mLabel;
QLineEdit *mLineEdit;
QStackedWidget stacked;
QString mText;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
QFormLayout *lay = new QFormLayout(&w);
MyEditableLabel el;
lay->addRow("MyEditableLabel: ", &el);
lay->addRow("QLineEdit: ", new QLineEdit);
w.show();
return a.exec();
}
#include "main.moc"