首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >是否有一个Qt小部件,看起来像一个标签来显示文本,但也可以编辑,如果双击?

是否有一个Qt小部件,看起来像一个标签来显示文本,但也可以编辑,如果双击?
EN

Stack Overflow用户
提问于 2018-07-07 04:37:18
回答 3查看 1.7K关注 0票数 1

我想在Qt的小工具,将像电子表格单元格的行为。它可以显示文本,然后当用户双击它时,它就变为可编辑的。一旦用户完成编辑并按Enter,文本就会被保存,并且该控件将不再可编辑。如果用户在编辑时按Escape,则控件将返回到其先前的值。

一种可能的解决方案是将QWidgetQLabelQLineEdit子类化。Qt中还有其他可用的解决方案吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-07-07 09:07:49

下面的版本也实现了与您的答案相同的功能,但是不是将QLineEditQLabel子类化,而是只使用eventFilter(),而不是手动管理可见性,让QStackedWidget来做。

代码语言:javascript
复制
#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"
票数 2
EN

Stack Overflow用户

发布于 2020-02-28 00:00:34

这个解决方案不那么吸引人,但您可以使用的性能更好的解决方案之一是使用QInputdialog更改QLabel并覆盖mouseDoubleClickEvent以触发输入对话框。我在这里的一些人已经了解到,没有办法从QLabel中拉出编辑过的文本。如果不更改QLabels内部代码,则不会。下面是一个使用QInputDialog作为方法的示例。

代码语言:javascript
复制
//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);
      }
}
票数 1
EN

Stack Overflow用户

发布于 2018-07-07 07:54:12

其中一个解决方案是拥有一个QLineEdit,并将其设置为只读,并以类似于标签的方式对其进行样式设置。我个人不喜欢这个解决方案,因为它更像是一种黑客方法。我想出了一些在我看来相当酷的东西,其中包括对QWidgetQLabelQLineEdit进行子类化

让我们首先介绍一个模型,该模型将在QWidget的子类版本中创建,该模型将被传递给它的子小部件,即QLabelQLineEdit的子类版本

模型标头- mymodel.h

代码语言:javascript
复制
#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

代码语言:javascript
复制
#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);
    }
}

正如我们所看到的,模型包含文本,这在QLabelQLineEdit中都是通用的,并且它有一个模式,可以是只读模式,也可以是编辑模式。

label实现是Label的子类。Header - mylabel.h

代码语言:javascript
复制
#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

代码语言:javascript
复制
#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

代码语言:javascript
复制
#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

代码语言:javascript
复制
#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);
}

现在我们有了模型,我们有了自己版本的QLabelQLineEdit。我们现在需要的是一个父小部件,它将包含这两个小部件,监听来自模型的信号,并根据这些信号更改其外观。该类是从QWidget派生的,名为MyEditableLabel

MyEditableLabel.h

代码语言:javascript
复制
#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“

代码语言:javascript
复制
#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方法。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51217294

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档