我想在Qt的小部件,将像一个电子表格单元格的行为。它可以显示文本,然后当用户双击它时,它变成可编辑的。用户完成编辑并按Enter键后,文本将被保存,控件将不再可编辑。如果用户在编辑时按Escape,则控件将返回到其先前的值。一种可能的解决办法是对QWidget、QLabel和QLineEdit进行子类化。Qt中是否有其他可用的解决方案?
QWidget
QLabel
QLineEdit
smtd7mpg1#
以下版本也实现了与您的答案相同的功能,但不是将QLineEdit和QLabel子类化,而是仅使用eventFilter(),而不是手动管理可见性,而是让QStackedWidget这样做。
eventFilter()
QStackedWidget
#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"
h6my8fg22#
您可以使用QInputdialog来更改QLabel并覆盖mouseDoubleClickEvent以触发输入对话框。我,正如这里的一些人所了解到的,没有办法从QLabel中拉取编辑过的文本。不改变QLabel的内部代码。下面是一个使用QInputDialog的例子,作为手段:
QInputdialog
mouseDoubleClickEvent
QInputDialog
//intrlbl.h #ifndef INTRLBL_H #define INTRLBL_H #include <QWidget> #include <QLabel> #include <QMouseEvent> class intrLbl: public QLabel { Q_OBJECT public: intrLbl(QWidget *parent); void mouseDoubleClickEvent(QMouseEvent *event) override; QString text; }; #endif // INTRLBL_H //intrlbl.cpp file #include "intrlbl.h" #include <QDebug> #include <QInputDialog> intrLbl::intrLbl(QWidget *parent) { this->setText("Text Changeable Via Double Click QInput Dialog"); this->setFocusPolicy(Qt::ClickFocus); this->setWordWrap(false); } void intrLbl::mouseDoubleClickEvent(QMouseEvent *event) { QString title = QInputDialog::getText(this, tr("Enter your Idea Title:"), tr("Title:"), QLineEdit::Normal, tr("enter your title here")); if(!title.isEmpty()) { qDebug() << "Title set to:" << title; this->setText(title); } else { title = "Title"; this->setText(title); } }
wz3gfoph3#
解决方案之一是有一个QLineEdit,并将其设置为只读,并以一种看起来像标签的方式对其进行样式化。我个人不喜欢这个解决方案,因为它更像是一种黑客方法。我想出了一些在我看来很酷的东西,其中包括子类QWidget,QLabel和QLineEdit:让我们首先介绍一个模型,它将在我们的QWidget的子类版本中创建,并且这个模型将被传递给其子widget,即QLabel和QLineEdit的子类版本:型号表头-mymodel.h:
mymodel.h
#ifndef MYMODEL_H #define MYMODEL_H #include <QObject> class MyModel : public QObject { Q_OBJECT Q_PROPERTY(Mode mode READ getMode WRITE setMode NOTIFY modeChanged) Q_PROPERTY(QString text READ getText WRITE setText NOTIFY textChanged) public: enum class Mode { ReadOnly = 0, Edit = 1, }; explicit MyModel(QObject* parent = nullptr); Mode getMode() const { return _mode; } const QString& getText() const { return _text; } signals: void modeChanged(Mode mode); void textChanged(const QString& text); public slots: void setMode(Mode mode); void setText(const QString& text); private: Mode _mode; QString _text; }; #endif // MYMODEL_H
模型实现-mymodel.cpp
mymodel.cpp
#include "mymodel.h" MyModel::MyModel(QObject *parent) : QObject(parent) , _mode(MyModel::Mode::ReadOnly) , _text(QString()) { } void MyModel::setMode(MyModel::Mode mode) { if (_mode != mode) { _mode = mode; emit modeChanged(_mode); } } void MyModel::setText(const QString &text) { if (_text != text) { _text = text; emit textChanged(text); } }
正如我们所看到的,该模型具有文本,这在QLabel和QLineEdit中都很常见,并且它具有一个模式,可以是只读模式或编辑模式。标签实现是Label的子类。标题-mylabel.h:
Label
mylabel.h
#ifndef MYLABEL_H #define MYLABEL_H #include <QLabel> #include <QSharedPointer> #include "mymodel.h" class MyLabel : public QLabel { Q_OBJECT public: explicit MyLabel(QWidget *parent = 0); void setModel(QSharedPointer<MyModel> model); protected: void mouseDoubleClickEvent(QMouseEvent *) override; private: QSharedPointer<MyModel> _model; }; #endif // MYLABEL_H
实施-mylabel.cpp:
mylabel.cpp
#include "mylabel.h" #include <QMouseEvent> MyLabel::MyLabel(QWidget *parent) : QLabel(parent) { } void MyLabel::setModel(QSharedPointer<MyModel> model) { _model = model; } void MyLabel::mouseDoubleClickEvent(QMouseEvent *) { _model->setText(text()); _model->setMode(MyModel::Mode::Edit); }
我们的类MyLabel有一个setModel()方法,它将从其父类中获取模型。我们覆盖了mouseDoubleClickEvent(),尽管我们将模型的文本设置为标签中的任何文本,并将模式设置为编辑,因为当双击时我们想要编辑文本。现在让我们来看看QLineEdit。我们的QLineEdit版本,称为MyLineEdit,正在监听键盘事件,当按下Enter和Esc键时,它要么将文本保存到模型中,要么将其丢弃。然后将模式更改为只读。MyLineEdit.h:
mouseDoubleClickEvent()
MyLineEdit
MyLineEdit.h
#ifndef MYLINEEDIT_H #define MYLINEEDIT_H #include <QLineEdit> #include <QSharedPointer> #include "mymodel.h" class MyLineEdit : public QLineEdit { Q_OBJECT public: MyLineEdit(QWidget* parent = nullptr); void setModel(QSharedPointer<MyModel> model); protected: void keyPressEvent(QKeyEvent* event) override; void focusOutEvent(QFocusEvent*); private: QSharedPointer<MyModel> _model; }; #endif // MYLINEEDIT_H
下面是实现-MyLineEdit.cpp:
MyLineEdit.cpp
#include "mylineedit.h" #include <QKeyEvent> MyLineEdit::MyLineEdit(QWidget *parent) : QLineEdit(parent) { } void MyLineEdit::setModel(QSharedPointer<MyModel> model) { _model = model; } void MyLineEdit::keyPressEvent(QKeyEvent *event) { if (event->key() == Qt::Key_Enter) { _model->setText(text()); _model->setMode(MyModel::Mode::ReadOnly); } else if (event->key() == Qt::Key_Escape) { _model->setMode(MyModel::Mode::ReadOnly); } else { QLineEdit::keyPressEvent(event); } } void MyLineEdit::focusOutEvent(QFocusEvent *) { _model->setText(text()); _model->setMode(MyModel::Mode::ReadOnly); }
现在我们有了模型,我们有了QLabel版本和QLineEdit版本。我们现在需要的是一个父控件,它将包含这两个控件,监听来自模型的信号,并根据信号更改其外观。这个类是从QWidget派生的,叫做MyEditableLabel:MyEditableLabel.h:
MyEditableLabel
MyEditableLabel.h
#ifndef MYEDITABLELABEL_H #define MYEDITABLELABEL_H #include <QSharedPointer> #include <QWidget> #include "mylabel.h" #include "mylineedit.h" class MyEditableLabel : public QWidget { Q_OBJECT public: explicit MyEditableLabel(QWidget *parent = nullptr); QString getText() const {return _text;} private: MyLabel *_label; MyLineEdit *_lineEdit; QSharedPointer<MyModel> _model; private slots: void onModeChanged(MyModel::Mode mode); void onTextChanged(const QString &text); private: QString _text; }; #endif // MYEDITABLELABEL_H
MyEditableLabel.cpp:#include“myeditablelabel.h”
MyEditableLabel.cpp
#include <QHBoxLayout> MyEditableLabel::MyEditableLabel(QWidget *parent) : QWidget(parent) { _model = QSharedPointer<MyModel>(new MyModel()); _model->setText("Click me!"); _label = new MyLabel(this); _label->setModel(_model); _lineEdit = new MyLineEdit(this); _lineEdit->setModel(_model); _lineEdit->setReadOnly(false); QHBoxLayout *mainLayout = new QHBoxLayout(); mainLayout->setMargin(0); mainLayout->setSpacing(0); mainLayout->addWidget(_label); mainLayout->addWidget(_lineEdit); setLayout(mainLayout); connect(_model.data(), &MyModel::modeChanged, this, &MyEditableLabel::onModeChanged); onModeChanged(_model->getMode()); connect(_model.data(), &MyModel::textChanged, this, &MyEditableLabel::onTextChanged); onTextChanged(_model->getText()); } void MyEditableLabel::onModeChanged(MyModel::Mode mode) { _lineEdit->setVisible(mode == MyModel::Mode::Edit); _lineEdit->selectAll(); _label->setVisible(mode == MyModel::Mode::ReadOnly); } void MyEditableLabel::onTextChanged(const QString &text) { _lineEdit->setText(text); _label->setText(text); _text = text; }
Usage:使用这个非常简单。如果你使用的是Qt Creator设计器,那么你想画一个QWidget,然后右键单击它并将其升级为MyEditableLabel,这样就完成了。如果你没有使用Qt Creator设计器,那么你只需要创建一个MyEditableLabel的示例,你就可以开始工作了。Improvements:最好不要在MyEditableLabel的构造函数中创建模型,而是在MyEditableLabel中有一个setModel方法。
Usage:
Qt Creator
Improvements:
setModel
3条答案
按热度按时间smtd7mpg1#
以下版本也实现了与您的答案相同的功能,但不是将
QLineEdit
和QLabel
子类化,而是仅使用eventFilter()
,而不是手动管理可见性,而是让QStackedWidget
这样做。h6my8fg22#
您可以使用
QInputdialog
来更改QLabel
并覆盖mouseDoubleClickEvent
以触发输入对话框。我,正如这里的一些人所了解到的,没有办法从
QLabel
中拉取编辑过的文本。不改变QLabel
的内部代码。下面是一个使用
QInputDialog
的例子,作为手段:wz3gfoph3#
解决方案之一是有一个QLineEdit,并将其设置为只读,并以一种看起来像标签的方式对其进行样式化。我个人不喜欢这个解决方案,因为它更像是一种黑客方法。我想出了一些在我看来很酷的东西,其中包括子类
QWidget
,QLabel
和QLineEdit
:让我们首先介绍一个模型,它将在我们的
QWidget
的子类版本中创建,并且这个模型将被传递给其子widget,即QLabel
和QLineEdit
的子类版本:型号表头-
mymodel.h
:模型实现-
mymodel.cpp
正如我们所看到的,该模型具有文本,这在
QLabel
和QLineEdit
中都很常见,并且它具有一个模式,可以是只读模式或编辑模式。标签实现是
Label
的子类。标题-mylabel.h
:实施-
mylabel.cpp
:我们的类MyLabel有一个setModel()方法,它将从其父类中获取模型。我们覆盖了
mouseDoubleClickEvent()
,尽管我们将模型的文本设置为标签中的任何文本,并将模式设置为编辑,因为当双击时我们想要编辑文本。现在让我们来看看
QLineEdit
。我们的QLineEdit
版本,称为MyLineEdit
,正在监听键盘事件,当按下Enter和Esc键时,它要么将文本保存到模型中,要么将其丢弃。然后将模式更改为只读。MyLineEdit.h
:下面是实现-
MyLineEdit.cpp
:现在我们有了模型,我们有了
QLabel
版本和QLineEdit
版本。我们现在需要的是一个父控件,它将包含这两个控件,监听来自模型的信号,并根据信号更改其外观。这个类是从QWidget
派生的,叫做MyEditableLabel
:MyEditableLabel.h
:MyEditableLabel.cpp
:#include“myeditablelabel.h”Usage:
使用这个非常简单。如果你使用的是Qt Creator
设计器,那么你想画一个QWidget
,然后右键单击它并将其升级为MyEditableLabel
,这样就完成了。如果你没有使用Qt Creator
设计器,那么你只需要创建一个MyEditableLabel
的示例,你就可以开始工作了。Improvements:
最好不要在MyEditableLabel
的构造函数中创建模型,而是在MyEditableLabel
中有一个setModel
方法。