You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在QML TableView中仅显示C++遗留TableModel的列子集(无需重写roleNames)

解决方案:无需修改LegacyModel的列子集显示方案

好的,这个问题我碰到过类似的情况——legacy模型和Qt::DisplayRole深度绑定,动它的代码风险太高,完全能理解你不想重构的诉求。这里有两种不用碰原模型roleNames()data()实现的方案,你可以根据场景选择:

方案一:QML层直接指定列索引获取数据

利用QML中QAbstractItemModel暴露的index()data()方法,你可以直接指定列索引来获取对应Qt::DisplayRole的数据,完全不需要修改C++代码。

比如你想显示原模型的第1列和第3列(索引从0开始),可以这么写:

TableView {
    anchors.fill: parent
    model: LegacyModel
    // 只定义你需要显示的列对应的delegate项
    delegate: RowLayout {
        implicitWidth: parent.width
        
        // 显示第1列数据
        Text {
            text: model.data(model.index(model.row, 1), Qt.DisplayRole)
            Layout.fillWidth: true
        }
        
        // 显示第3列数据
        Text {
            text: model.data(model.index(model.row, 3), Qt.DisplayRole)
            Layout.fillWidth: true
        }
    }
}

这个方案的优点是快速简单,适合只需要在单个视图里显示少量列的场景;缺点是如果要显示的列较多,或者需要复用这个列过滤逻辑,代码会比较冗余。

方案二:轻量级列过滤代理模型(推荐)

如果需要复用列过滤逻辑,或者要显示的列较多,可以写一个极简的QAbstractProxyModel子类,只负责映射你需要的列,完全不修改原模型的任何代码。

C++代理模型代码

#include <QAbstractProxyModel>
#include <QList>

class ColumnFilterProxyModel : public QAbstractProxyModel
{
    Q_OBJECT
    // 暴露给QML的可见列属性,直接设置原模型的列索引列表即可
    Q_PROPERTY(QList<int> visibleColumns READ visibleColumns WRITE setVisibleColumns NOTIFY visibleColumnsChanged)

public:
    explicit ColumnFilterProxyModel(QObject *parent = nullptr) 
        : QAbstractProxyModel(parent) {}

    QList<int> visibleColumns() const { return m_visibleColumns; }
    void setVisibleColumns(const QList<int>& cols) {
        if (m_visibleColumns != cols) {
            beginResetModel();
            m_visibleColumns = cols;
            endResetModel();
            emit visibleColumnsChanged();
        }
    }

    // 重写代理模型的核心映射方法
    QModelIndex mapToSource(const QModelIndex& proxyIndex) const override {
        if (!proxyIndex.isValid() || proxyIndex.column() >= m_visibleColumns.size())
            return QModelIndex();
        return sourceModel()->index(proxyIndex.row(), m_visibleColumns.at(proxyIndex.column()), proxyIndex.parent());
    }

    QModelIndex mapFromSource(const QModelIndex& sourceIndex) const override {
        int proxyCol = m_visibleColumns.indexOf(sourceIndex.column());
        if (proxyCol == -1) return QModelIndex();
        return index(sourceIndex.row(), proxyCol, sourceIndex.parent());
    }

    // 重写列数、行数、数据获取等方法
    int columnCount(const QModelIndex& parent = QModelIndex()) const override {
        Q_UNUSED(parent);
        return m_visibleColumns.size();
    }

    int rowCount(const QModelIndex& parent = QModelIndex()) const override {
        return sourceModel() ? sourceModel()->rowCount(parent) : 0;
    }

    QVariant data(const QModelIndex& proxyIndex, int role = Qt::DisplayRole) const override {
        // 直接转发到原模型的对应列
        return sourceModel()->data(mapToSource(proxyIndex), role);
    }

    QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override {
        if (orientation == Qt::Horizontal) {
            return sourceModel()->headerData(m_visibleColumns.at(section), orientation, role);
        }
        return sourceModel()->headerData(section, orientation, role);
    }

signals:
    void visibleColumnsChanged();

private:
    QList<int> m_visibleColumns;
};

在QML中使用代理模型

首先在main.cpp里注册这个代理模型:

#include "ColumnFilterProxyModel.h"
// ...
qmlRegisterType<ColumnFilterProxyModel>("YourNamespace", 1, 0, "ColumnFilterProxyModel");

然后在QML里直接配置要显示的列:

import YourNamespace 1.0

TableView {
    anchors.fill: parent
    model: ColumnFilterProxyModel {
        sourceModel: LegacyModel
        // 这里设置你需要显示的原模型列索引
        visibleColumns: [1, 3, 5]
    }
    delegate: RowLayout {
        implicitWidth: parent.width
        // 用Repeater自动生成所有可见列的Text
        Repeater {
            model: model.columnCount
            Text {
                text: model.display
                Layout.fillWidth: true
                // 可以根据列索引设置样式等
                color: index === 0 ? "blue" : "black"
            }
        }
    }
}

这个方案的优点是代码可复用,逻辑清晰,而且完全遵循开闭原则——原模型的代码一行都不用改,所有过滤逻辑都在代理层实现,后续要调整显示的列只需要修改QML里的visibleColumns列表即可。


内容的提问来源于stack exchange,提问作者jusko

火山引擎 最新活动