在 QTableView 中设置 QPlainTextEdit 委托的高度

发布于 2024-12-05 05:21:04 字数 696 浏览 0 评论 0原文

我正在这里从事一个项目,目前我遇到了以下问题。 它是关于一个 QTableView,它有一个名为“Description”的列,该列的单元格包含一个 QPlainTextEditDelegate。每次输入 QPlainTextEdit 时我都无法设置它的高度。现在它的行为就像一个 QLineEdit ,直到我将 QTableView 的行(当时我在其中处于活动状态)拖动得更大。

我想要做的是在输入 QPlainTextEdit 后更改它的高度。 您有什么建议?我怎样才能继续完成这件事?

提前谢谢大家!

顺便说一句,对不起我的英语不好:/

编辑:

好的我解决了它,但没有 sizeHint,我使用了 updateEditorGeometry :

void updateEditorGeometry( QWidget* editor, const QStyleOptionViewItem & option, const QModelIndex & index ) const;

在这个方法中,您可以根据需要设置宽度或高度

editor->setGeometry(option.rect.x(),option.rect.y(),,);

不过还是谢谢你!

I'm working here on a project and currently I'm stuck on the following problem.
It is about a QTableView which has a column called "Description", the cells of this column contain a QPlainTextEditDelegate. I'm failing on setting the Height of the QPlainTextEdit everytime it is entered. Right now it behaves like a QLineEdit until I drag the row ( in which I'm active at that time ) of the QTableView larger.

What I want to do is to change the Height of the QPlainTextEdit once I entered it.
What are your suggestions? How can I proceed to get this thing done?

Thank you all in advance!

BTW Sorry for my poor english :/

edit:

Ok I solved it, but without sizeHint, I used updateEditorGeometry :

void updateEditorGeometry( QWidget* editor, const QStyleOptionViewItem & option, const QModelIndex & index ) const;

And inside this Method, you can set the width or height like you want

editor->setGeometry(option.rect.x(),option.rect.y(),<your_width>,<your_height>);

But thank you anyway!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

凶凌 2024-12-12 05:21:04

您应该在创建编辑器时重新实现 QAbstractItemDelegate::sizeHint 方法以返回预期高度。我认为创建编辑器后没有必要发出 QAbstractItemDelegate::sizeHintChanged 信号,但文档没有说明任何内容。如果没有它就无法工作,您应该在返回创建的编辑器小部件后发出 sizeHintChanged 以通知视图需要更改行高。

You should reimplement QAbstractItemDelegate::sizeHint method to return expected height when you create your editor. I don't think that it's necesary to emit QAbstractItemDelegate::sizeHintChanged signal after creating editor, but documentation doesn't say anything. If it doesn't work without it, you should emit sizeHintChanged after returning created editor widget to notify view of need to change row height.

绝情姑娘 2024-12-12 05:21:04

我面临着完全相同的问题,尽管 QTableView 中有一个自定义委托,其中有一个 QPlainTextEdit 作为编辑器。最初,编辑器的大小不会超出其表格单元格的大小。

什么对我不起作用:

  • updateEditorGeometry():仅在初始show()时调用
  • 自定义sizeHint():从未被调用,无论是在子类还是基类中,无论任何 update()updateGeometry() 调用或信号

在看似无穷无尽的时间收集有关一些未记录的 QPlainTextEdit/QTextDocument 的小块信息之后“功能”和 Qt 怪癖我通过连接到 QPlainTextEdit-> 得到了我想要的东西document()->documentLayout()documentSizeChanged(QSizeF) 信号。

以下是根据需要扩展编辑器同时将其限制为父 QTableView 视口 (m_pTableView) 的要点。

希望这对任何人都有意义。示例代码不能按原样编译,但应该提供足够的提示来开始使用。

h 编辑器 + 委托

#include <QPlainTextEdit>

// A custom QStyledItemDelegate
#include "library/tableitemdelegate.h"

/// A QPlainTextEdit to show all content lines in a scrollable view.
/// * finish editing with Return (like QLineEdit used for other metadata)
/// * add new line with Shift+Return.
/// Horizontal scrollbar is hidden as long as content is just one line.
/// Note: QTextEdit is no option here since it seems to transform content with
/// line breaks to html doc when committing data.
class MultiLineEditor : public QPlainTextEdit {
    Q_OBJECT
  public:
    MultiLineEditor(QWidget* pParent);

    bool eventFilter(QObject* obj, QEvent* event) override;

  signals:
    void editingFinished();
};

class MultiLineEditDelegate : public TableItemDelegate {
    Q_OBJECT
  public:
    explicit MultiLineEditDelegate(QTableView* pTrackTable);
    ~MultiLineEditDelegate() override = default;

    // called when the user starts editing an item
    QWidget* createEditor(QWidget* parent,
            const QStyleOptionViewItem& option,
            const QModelIndex& index) const override;

  private slots:
    void commitAndCloseEditor();

  private:
    void adjustEditor(MultiLineEditor* pEditor, const QSizeF size) const;
    mutable QRect m_editRect;
    mutable int m_lineCount;
};

cpp 编辑器 + 委托

#include "library/multilineeditdelegate.h"

#include <QAbstractTextDocumentLayout>
#include <cmath>

#include "moc_multilineeditdelegate.cpp"

MultiLineEditor::MultiLineEditor(QWidget* pParent)
        : QPlainTextEdit(pParent) {
    setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
    // Disable line wrap for a predictable view (like QLineEdit).
    // Horizontal scrollbars show up automatically.
    setLineWrapMode(QPlainTextEdit::NoWrap);
    // Remove ugly content offset, most notable with one-liners
    setContentsMargins(0, 0, 0, 0);
    document()->setDocumentMargin(0);
    // Add event filter to catch right-clicks and key presses
    installEventFilter(this);
};

bool MultiLineEditor::eventFilter(QObject* obj, QEvent* event) {
    if (event->type() == QEvent::MouseButtonPress) {
        // Work around a strange quirk: right-clicks outside the rectangle of
        // the underlying table index are not triggering the context menu.
        // Simply returning true fixes it.
        QMouseEvent* me = static_cast<QMouseEvent*>(event);
        if (me->button() == Qt::RightButton &&
                 rect().contains(me->pos(), false)) {
            return true;
        }
    } else if (event->type() == QEvent::KeyPress) {
        // Finish editing with Return key like in QLineEdit
        QKeyEvent* ke = static_cast<QKeyEvent*>(event);
        if ((ke->key() == Qt::Key_Return || ke->key() == Qt::Key_Enter) &&
                ke->modifiers().testFlag(Qt::NoModifier)) {
            emit editingFinished();
            return false;
        }
    }
    return QPlainTextEdit::eventFilter(obj, event);
}

MultiLineEditDelegate::MultiLineEditDelegate(QTableView* pTableView)
        : TableItemDelegate(pTableView),
          m_lineCount(0) {
}

QWidget* MultiLineEditDelegate::createEditor(QWidget* pParent,
        const QStyleOptionViewItem& option,
        const QModelIndex& index) const {
    Q_UNUSED(index);
    auto* pEditor = new MultiLineEditor(pParent);
    auto* pDocLayout = pEditor->document()->documentLayout();
    // Adjust height to fit content and maybe shift vertically to fit into the
    // library view. documentSizeChanged() is emitted when text changed, incl.
    // initial fill.
    // We could also connect to QPlainTextEdit::blockCountChanged(), though
    // for some reason, that only works for documents with 2+ lines
    // appending line breaks to single-line docs won't fire that signal :|
    connect(pDocLayout,
            &QAbstractTextDocumentLayout::documentSizeChanged,
            this,
            [this, pEditor](const QSizeF size) {
                adjustEditor(pEditor, size);
            });
    // emitted when pressing Return key to act like QLineEdit
    connect(pEditor,
            &MultiLineEditor::editingFinished,
            this,
            &MultiLineEditDelegate::commitAndCloseEditor);
    // Store the initial rectangle so we can read the x/y origin and in adjustEditor()
    m_editRect = option.rect;
    return pEditor;
}

void MultiLineEditDelegate::adjustEditor(MultiLineEditor* pEditor, const QSizeF size) const {
    // Compared to QTextEdit, size.height() is the line count (Qt speak: blocks)
    int newLineCount = static_cast<int>(round(size.height()));
    // Only act if line count changed
    if (newLineCount == m_lineCount) {
        return;
    } else {
        m_lineCount = newLineCount;
    }

    // Remove the scrollbars if content is just one line to emulate QLineEdit
    // appearace, else enable auto mode.
    Qt::ScrollBarPolicy pol(m_lineCount > 1 ? Qt::ScrollBarAsNeeded : Qt::ScrollBarAlwaysOff);
    pEditor->setVerticalScrollBarPolicy(pol);
    pEditor->setHorizontalScrollBarPolicy(pol);

    // Calculate the content height
    int lines = m_lineCount;
    // Add extra margin so the horizontal scrollbar doesn't obstruct the last
    // line (which also avoids the vertical scrollbar as long as possible)
    lines += lines > 1 ? 1 : 0;

    QFontMetrics fm(pEditor->document()->defaultFont());
    int newH = fm.lineSpacing() * lines;

    // Limit editor to visible table height
    int tableH = m_pTableView->viewport()->rect().height();
    newH = std::min(newH, tableH);
    // If the editor overflows the table view, move it up so it's not clipped.
    // No need to care about y < 0 or y > (table height - line height) since the
    // table already ensures visibility when the index is selected.
    int newY = m_editRect.y();
    if ((newY + newH) > tableH) {
        newY = tableH - newH;
    }
    // Also limit width so scrollbars are visible and table is not scrolled if
    // cursor is moved horizontally.
    int newW = std::min(pEditor->width(), m_pTableView->viewport()->rect().width());

    pEditor->setGeometry(QRect(m_editRect.x(), newY, newW, newH));
}

void MultiLineEditDelegate::commitAndCloseEditor() {
    MultiLineEditor* pEditor = qobject_cast<MultiLineEditor*>(sender());
    emit commitData(pEditor);
    emit closeEditor(pEditor);
}

I was facing the exact same issue, though with a custom delegate inside a QTableView which has a QPlainTextEdit as editor. Initailly, the editor would not grow beyond the size of its table cell.

What did not work for me:

  • updateEditorGeometry(): was only called on initial show()
  • custom sizeHint(): wasn't called ever, neither in subclass or baseclass, regardless any update(), updateGeometry() calls or signals

After seemingly endless hours of collecting small chunks of info about some undocumented QPlainTextEdit/QTextDocument 'features' and Qt quirks I got what I want by connecting to QPlainTextEdit->document()->documentLayout()'s documentSizeChanged(QSizeF) signal.

Below are the essentials to expand the editor as desired while limiting it to the parent QTableView's viewport (m_pTableView).

Hope this makes sense to anyone. Example code is not compilable as is but should give enough hints to get started.

h editor + delegate

#include <QPlainTextEdit>

// A custom QStyledItemDelegate
#include "library/tableitemdelegate.h"

/// A QPlainTextEdit to show all content lines in a scrollable view.
/// * finish editing with Return (like QLineEdit used for other metadata)
/// * add new line with Shift+Return.
/// Horizontal scrollbar is hidden as long as content is just one line.
/// Note: QTextEdit is no option here since it seems to transform content with
/// line breaks to html doc when committing data.
class MultiLineEditor : public QPlainTextEdit {
    Q_OBJECT
  public:
    MultiLineEditor(QWidget* pParent);

    bool eventFilter(QObject* obj, QEvent* event) override;

  signals:
    void editingFinished();
};

class MultiLineEditDelegate : public TableItemDelegate {
    Q_OBJECT
  public:
    explicit MultiLineEditDelegate(QTableView* pTrackTable);
    ~MultiLineEditDelegate() override = default;

    // called when the user starts editing an item
    QWidget* createEditor(QWidget* parent,
            const QStyleOptionViewItem& option,
            const QModelIndex& index) const override;

  private slots:
    void commitAndCloseEditor();

  private:
    void adjustEditor(MultiLineEditor* pEditor, const QSizeF size) const;
    mutable QRect m_editRect;
    mutable int m_lineCount;
};

cpp editor + delegate

#include "library/multilineeditdelegate.h"

#include <QAbstractTextDocumentLayout>
#include <cmath>

#include "moc_multilineeditdelegate.cpp"

MultiLineEditor::MultiLineEditor(QWidget* pParent)
        : QPlainTextEdit(pParent) {
    setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
    // Disable line wrap for a predictable view (like QLineEdit).
    // Horizontal scrollbars show up automatically.
    setLineWrapMode(QPlainTextEdit::NoWrap);
    // Remove ugly content offset, most notable with one-liners
    setContentsMargins(0, 0, 0, 0);
    document()->setDocumentMargin(0);
    // Add event filter to catch right-clicks and key presses
    installEventFilter(this);
};

bool MultiLineEditor::eventFilter(QObject* obj, QEvent* event) {
    if (event->type() == QEvent::MouseButtonPress) {
        // Work around a strange quirk: right-clicks outside the rectangle of
        // the underlying table index are not triggering the context menu.
        // Simply returning true fixes it.
        QMouseEvent* me = static_cast<QMouseEvent*>(event);
        if (me->button() == Qt::RightButton &&
                 rect().contains(me->pos(), false)) {
            return true;
        }
    } else if (event->type() == QEvent::KeyPress) {
        // Finish editing with Return key like in QLineEdit
        QKeyEvent* ke = static_cast<QKeyEvent*>(event);
        if ((ke->key() == Qt::Key_Return || ke->key() == Qt::Key_Enter) &&
                ke->modifiers().testFlag(Qt::NoModifier)) {
            emit editingFinished();
            return false;
        }
    }
    return QPlainTextEdit::eventFilter(obj, event);
}

MultiLineEditDelegate::MultiLineEditDelegate(QTableView* pTableView)
        : TableItemDelegate(pTableView),
          m_lineCount(0) {
}

QWidget* MultiLineEditDelegate::createEditor(QWidget* pParent,
        const QStyleOptionViewItem& option,
        const QModelIndex& index) const {
    Q_UNUSED(index);
    auto* pEditor = new MultiLineEditor(pParent);
    auto* pDocLayout = pEditor->document()->documentLayout();
    // Adjust height to fit content and maybe shift vertically to fit into the
    // library view. documentSizeChanged() is emitted when text changed, incl.
    // initial fill.
    // We could also connect to QPlainTextEdit::blockCountChanged(), though
    // for some reason, that only works for documents with 2+ lines
    // appending line breaks to single-line docs won't fire that signal :|
    connect(pDocLayout,
            &QAbstractTextDocumentLayout::documentSizeChanged,
            this,
            [this, pEditor](const QSizeF size) {
                adjustEditor(pEditor, size);
            });
    // emitted when pressing Return key to act like QLineEdit
    connect(pEditor,
            &MultiLineEditor::editingFinished,
            this,
            &MultiLineEditDelegate::commitAndCloseEditor);
    // Store the initial rectangle so we can read the x/y origin and in adjustEditor()
    m_editRect = option.rect;
    return pEditor;
}

void MultiLineEditDelegate::adjustEditor(MultiLineEditor* pEditor, const QSizeF size) const {
    // Compared to QTextEdit, size.height() is the line count (Qt speak: blocks)
    int newLineCount = static_cast<int>(round(size.height()));
    // Only act if line count changed
    if (newLineCount == m_lineCount) {
        return;
    } else {
        m_lineCount = newLineCount;
    }

    // Remove the scrollbars if content is just one line to emulate QLineEdit
    // appearace, else enable auto mode.
    Qt::ScrollBarPolicy pol(m_lineCount > 1 ? Qt::ScrollBarAsNeeded : Qt::ScrollBarAlwaysOff);
    pEditor->setVerticalScrollBarPolicy(pol);
    pEditor->setHorizontalScrollBarPolicy(pol);

    // Calculate the content height
    int lines = m_lineCount;
    // Add extra margin so the horizontal scrollbar doesn't obstruct the last
    // line (which also avoids the vertical scrollbar as long as possible)
    lines += lines > 1 ? 1 : 0;

    QFontMetrics fm(pEditor->document()->defaultFont());
    int newH = fm.lineSpacing() * lines;

    // Limit editor to visible table height
    int tableH = m_pTableView->viewport()->rect().height();
    newH = std::min(newH, tableH);
    // If the editor overflows the table view, move it up so it's not clipped.
    // No need to care about y < 0 or y > (table height - line height) since the
    // table already ensures visibility when the index is selected.
    int newY = m_editRect.y();
    if ((newY + newH) > tableH) {
        newY = tableH - newH;
    }
    // Also limit width so scrollbars are visible and table is not scrolled if
    // cursor is moved horizontally.
    int newW = std::min(pEditor->width(), m_pTableView->viewport()->rect().width());

    pEditor->setGeometry(QRect(m_editRect.x(), newY, newW, newH));
}

void MultiLineEditDelegate::commitAndCloseEditor() {
    MultiLineEditor* pEditor = qobject_cast<MultiLineEditor*>(sender());
    emit commitData(pEditor);
    emit closeEditor(pEditor);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文