Qt 在 QTableView 单元格内设置自定义小部件

问题描述 投票:0回答:3

我想将自定义小部件放入

QTableView
的单元格中。 Widget 可以是
QPushButton
、复选框或其他东西。我尝试过以下方法,但没有人能让我满意:

  1. 使用委托。该策略可以绘制小部件,但不能是自定义小部件,并且无法交互。
  2. 使用
    QTableView::setIndexWidget()
    。使用此策略,自定义小部件完全覆盖单元格,绑定到
    QTableView
    的委托不起作用,这意味着 a-double-click() 不会在单元格上进行编辑操作。

请注意,该功能是独立的,就像插件一样。所以我不能做以下事情。

  1. 继承自
    QTableView
    。我只能得到与
    QTableView
    绑定的指针变量——只能是
    QTableView
    的对象。
  2. 继承任何模型。模型是由其他用户控制的,编写模型的程序员不应该也不可能只使用我自定义的模型。

问题确实很复杂,太多的约束限制了设计。

c++ qt qtableview
3个回答
2
投票

如果您想使用模型/视图来包含小部件的数据,则没有委托就无法执行此操作。更糟糕的是,如果您尝试这样做,当元素数量非常多时,您的程序将会显着减慢,因为每个小部件都会参与事件循环。这不是你想要的。您希望涉及用户可见的小部件。

考虑阅读本文以获取更多解释。


1
投票

感谢大家对这个问题的贡献,我找到了解决这个问题的方法。 按照“原来的想法”解决了,就是在tableView上画一个QToolButton,使用QModelIndex。通过 QModelIndex,我可以获得可以绘制任何 QWidget 的几何位置。然而,这个方法确实很复杂,因为我必须维护 QModelIndex 的更改,例如removeColumns和insertColumns。

另一个问题是我必须区分隐藏和删除列或行。我想我应该发布另一个新问题来寻求帮助。 再次感谢。


0
投票

您应该子类化 QTableView 和 QItemDelegate:

在表格视图中,您应该为可见区域中的所有单元格打开持久编辑器并相应地更新主题:

表格视图.h

#ifndef TABLE_VIEW_H
#define TABLE_VIEW_H

#include <QTableView>

class TableView : public QTableView
{
    Q_OBJECT

public:
    TableView(QWidget* parent = nullptr);

    void setModel(QAbstractItemModel* model) override;
    void scrollContentsBy(int dx, int dy) override;
    void scrollTo(const QModelIndex& index, ScrollHint hint) override;

protected slots:
    void resizeEvent(QResizeEvent* event) override;
    void dataChanged(const QModelIndex&  topLeft,
                     const QModelIndex&  bottomRight,
                     const QVector<int>& roles) override;
    void rowsInserted(const QModelIndex& parent, int start, int end) override;

private:
    void showAllVisiblePersistentEditors();
    QModelIndexList m_editor_list;
};

#endif // TABLE_VIEW_H

表视图.cpp

TableView::TableView(QWidget* parent) :
    QTableView(parent)
{
    setItemDelegate(new Delegate);
}

void TableView::setModel(QAbstractItemModel* model)
{
    QTableView::setModel(model);
    executeDelayedItemsLayout();
    showAllVisiblePersistentEditors();
}

void TableView::scrollContentsBy(int dx, int dy)
{
    QTableView::scrollContentsBy(dx, dy);
    showAllVisiblePersistentEditors();
}

void TableView::scrollTo(const QModelIndex& index, ScrollHint hint)
{
    QTableView::scrollTo(index, hint);
    showAllVisiblePersistentEditors();
}

void TableView::resizeEvent(QResizeEvent* event)
{
    QTableView::resizeEvent(event);
    executeDelayedItemsLayout();
    showAllVisiblePersistentEditors();
}

void TableView::dataChanged(const QModelIndex&  topLeft,
                            const QModelIndex&  bottomRight,
                            const QVector<int>& roles)
{
    QTableView::dataChanged(topLeft, bottomRight, roles);
    showAllVisiblePersistentEditors();
}

void TableView::rowsInserted(const QModelIndex& parent, int start, int end)
{
    QTableView::rowsInserted(parent, start, end);
    showAllVisiblePersistentEditors();
}

void TableView::showAllVisiblePersistentEditors()
{
    const auto* model { this->model() };

    if (model) {
        const auto rect { viewport()->rect() };

        const auto first_index { indexAt(rect.topLeft()) };

        const auto valid_bottom_right {
            visualRect(model->index(model->rowCount() - 1, model->columnCount() - 1))
            .bottomRight() };
        const auto bottom_right { rect.bottomRight() };
        const auto last_index { indexAt({ std::min(bottom_right.x(), valid_bottom_right.x()),
                                          std::min(bottom_right.y(), valid_bottom_right.y()) }) };

        const auto r1 { first_index.row() };
        const auto r2 { last_index.row() };
        const auto c1 { first_index.column() };
        const auto c2 { last_index.column() };

        QModelIndex index;

        const auto editor_count { m_editor_list.size() };
        for (auto i { editor_count - 1 }; i >= 0; --i) {
            index = qAsConst(m_editor_list)[i];
            if (!visualRect(index).intersects(rect)) {
                closePersistentEditor(index);
                m_editor_list.removeLast();
            }
        }

        for (auto r { r1 }; r <= r2; ++r) {
            for (auto c { c1 }; c <= c2; ++c) {
                index = model->index(r, c);
                if (index.flags().testFlag(Qt::ItemIsEditable) &&
                    visualRect(index).intersects(rect) &&
                    !isPersistentEditorOpen(index))
                {
                    m_editor_list.push_back(index);
                    openPersistentEditor(index);
                }
            }
        }
    }
}

在委托中,您可以为编辑器提供您喜欢的任何小部件:

委托.h

#ifndef DELEGATE_H
#define DELEGATE_H

#include <QAbstractItemDelegate>

class Delegate : public QAbstractItemDelegate
{
    Q_OBJECT

public:
    Delegate(QObject* parent = nullptr);

    void paint(QPainter*                   painter,
               const QStyleOptionViewItem& option,
               const QModelIndex&          index) const override;

    QSize sizeHint(const QStyleOptionViewItem& option,
                   const QModelIndex&          index) const override;

    QWidget* createEditor(QWidget*                    parent,
                          const QStyleOptionViewItem& option,
                          const QModelIndex&          index) const override;

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

#endif // DELEGATE_H

委托.cpp

#include "delegate.h"

#include <QPushButton>

Delegate::Delegate(QObject* parent) :
    QAbstractItemDelegate(parent)
{}

void Delegate::paint(QPainter*                   painter,
                     const QStyleOptionViewItem& option,
                     const QModelIndex&          index) const
{
    Q_UNUSED(painter)
    Q_UNUSED(option)
    Q_UNUSED(index)
}

QSize Delegate::sizeHint(const QStyleOptionViewItem& option,
                         const QModelIndex&          index) const
{
    Q_UNUSED(index)
    return option.decorationSize;
}

QWidget* Delegate::createEditor(QWidget*                    parent,
                                const QStyleOptionViewItem& option,
                                const QModelIndex&          index) const
{
    Q_UNUSED(option)
    Q_UNUSED(index)
    return new QPushButton(parent);
}

void Delegate::updateEditorGeometry(QWidget*                    editor,
                                    const QStyleOptionViewItem& option,
                                    const QModelIndex&          index) const
{
    Q_UNUSED(index)
    editor->setGeometry(option.rect);
}
© www.soinside.com 2019 - 2024. All rights reserved.