我想在Qt的小工具,将像电子表格单元格的行为。它可以显示文本,然后当用户双击它时,它就变为可编辑的。一旦用户完成编辑并按Enter,文本就会被保存,并且该控件将不再可编辑。如果用户在编辑时按Escape,则控件将返回到其先前的值。
一种可能的解决方案是将QWidget
、QLabel
和QLineEdit
子类化。Qt中还有其他可用的解决方案吗?
发布于 2018-07-07 09:07:49
下面的版本也实现了与您的答案相同的功能,但是不是将QLineEdit
和QLabel
子类化,而是只使用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"
发布于 2020-02-28 00:00:34
这个解决方案不那么吸引人,但您可以使用的性能更好的解决方案之一是使用QInputdialog更改QLabel并覆盖mouseDoubleClickEvent以触发输入对话框。我在这里的一些人已经了解到,没有办法从QLabel中拉出编辑过的文本。如果不更改QLabels内部代码,则不会。下面是一个使用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);
}
}
发布于 2018-07-07 07:54:12
其中一个解决方案是拥有一个QLineEdit,并将其设置为只读,并以类似于标签的方式对其进行样式设置。我个人不喜欢这个解决方案,因为它更像是一种黑客方法。我想出了一些在我看来相当酷的东西,其中包括对QWidget
、QLabel
和QLineEdit
进行子类化
让我们首先介绍一个模型,该模型将在QWidget
的子类版本中创建,该模型将被传递给它的子小部件,即QLabel
和QLineEdit
的子类版本
模型标头- 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
#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实现是Label
的子类。Header - 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
#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
#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
#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
#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“
#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
方法。
https://stackoverflow.com/questions/51217294
复制相似问题