c++ - 在 Qt5 中实现基于单元格的小部件

标签 c++ qt qt5

我正在尝试实现一个类似于 Jupyter Notebook 中的基于单元格的小部件在 Qt 中,多个单元格垂直堆叠。每个单元格都由一个 QTextEdit 和多个按钮组成,单元格的垂直大小会随着在文本编辑中输入更多文本而增加(即文本编辑中没有垂直滚动条)。

但是我不确定在 Qt 中实现这样一个小部件的最佳方法是什么。我已经为每个项目尝试了一个带有自定义小部件(由 QTextEdit 和几个按钮组成)的 QListWidget,但是自定义小部件不会通过输入垂直增长更多文本,而不是 QTextEdit 滚动条会出现。我还使用 QListViewQStyledItemDelegate 实现了第二个版本,但是我遇到了多个问题,包括无法与绘制的按钮交互(通过委托(delegate))。

有关如何实现这种基于单元格的小部件的任何建议/示例?

最佳答案

您可以继承 QTextEdit 并使用 document()->size() 监听 document 大小的变化(不是大小QTextEdit,注意)。然后您可以调整 QTextEdit 父级的大小以反射(reflect)新的大小。要用小部件填充父级,请使用布局。为此,我在下面多次使用了 QVBoxLayout。 (一,在垂直列中容纳多个 QTextEdit 小部件;二,容纳单个 TextEdit)。

#include <QtCore>
#include <QtWidgets>

class DyTextEdit : public QTextEdit
{
    Q_OBJECT
public:
    DyTextEdit(QWidget *parent = nullptr) :
        QTextEdit(parent)
    {
        QTextDocument *doc = document();
        currentSize = doc->size();

        qDebug() << "[Init] Size:" << currentSize;

        //  listen to text/content changes
        connect(this, &QTextEdit::textChanged, this, &DyTextEdit::on_textChanged);

        //  connect <> 💡
        connect(this, &DyTextEdit::sizeChanged, this, &DyTextEdit::resizeParent);

        doc->setTextWidth(-1);

        emit sizeChanged(currentSize);  //  init
    }

signals:
    //  emitted when document size changes
    void sizeChanged(QSizeF size);

public slots:
    void on_textChanged()
    {
        QSizeF newSize = document()->size();

        qDebug() << "[TextChanged] Size:" << newSize;

        //  detect changes in the document size
        if (newSize != currentSize)
            emit sizeChanged(newSize);  //  emit signal💡

        //  update size
        currentSize = newSize;
    }

    void resizeParent(QSizeF size)
    {
        //  resize the parent's height, don't bother with the width
        parentWidget()->setFixedHeight(size.height());
    }

private:
    QSizeF currentSize; //  keeps track of current document size

};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    //  holds all dytextedits
    QWidget aggregateWidget;
    QVBoxLayout aggregateLayout(&aggregateWidget);

    //  note: for scalability, use a QList (or QLists)

    //  first textbox
    QWidget widget;
    QVBoxLayout vbLayout(&widget);
    vbLayout.setMargin(0);
    DyTextEdit dytext(&widget);
    vbLayout.addWidget(&dytext);

    //  first button row
    QHBoxLayout hbLayout(&widget);
    hbLayout.setMargin(0);
    QPushButton pb1a("Push this.", &widget);
    hbLayout.addWidget(&pb1a);
    QPushButton pb1b("Push this.", &widget);
    hbLayout.addWidget(&pb1b);

    //  second textbox
    QWidget widget2;
    QVBoxLayout vbLayout2(&widget2);
    vbLayout2.setMargin(0);
    DyTextEdit dytext2(&widget2);
    vbLayout2.addWidget(&dytext2);

    //  second button row
    QHBoxLayout hbLayout2(&widget2);
    hbLayout2.setMargin(0);
    QPushButton pb2a("Push this.", &widget2);
    hbLayout2.addWidget(&pb2a);
    QPushButton pb2b("Push this.", &widget2);
    hbLayout2.addWidget(&pb2b);

    //  add widgets to layout
    aggregateLayout.addWidget(&widget);     //  cell 1
    aggregateLayout.addLayout(&hbLayout);   //  |
    aggregateLayout.addWidget(&widget2);    //  cell 2
    aggregateLayout.addLayout(&hbLayout2);  //  |

    aggregateLayout.setSizeConstraint(QLayout::SetMinAndMaxSize);

    aggregateWidget.show();

    return a.exec();
}

#include "main.moc" //  include if there are QObject classes in main.cpp

请注意,在上面,我使用了使用 QHBoxLayout 的按钮行,并将它们添加到与文本框小部件分离的整体聚合布局中。如果您想以不同的格式设置按钮,您仍然可以使用 QGridLayout。您还可以将文本编辑器和按钮布局组合为覆盖两者的另一个小部件(作为保护伞)下的子项。这将更清楚地形成小部件的单元格,并且可能更容易四处移动。 (我已经在 Github 上上传了一个可行的示例。)

演示(macOS):

这是输入内容和复制粘贴内容后的截图。

demonstration using both typed and copied content

请注意,聚合小部件将在删除文本行时收缩。

关于c++ - 在 Qt5 中实现基于单元格的小部件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53800168/

相关文章:

c++ - QScrollArea 中 QBoxLayout 中固定大小的小部件

c++ - 从键码中获取键名(X11 XGrabKey)

c++ - 如何在 Linux 中为 Qt 应用程序制作控制台 cmd?

c++ - 如何获得光标形状?

c++ - 具有巨大随机数的桶排序

c++ - OpenGL 导入 PNG 变暗

c++ - 函数传递后 DirectX::XMMATRIX 乘法不正确 (C++)

c++ - QImage 出现错误,尽管我正在阻止它

c++ - 使用 OpenGL 显示 YUY2 (Y'UV422)

c++ - fflush - 如何检查最后一个操作是否为输出操作