如何在两个视图展示QFileSystemModel:树视图及选中项的列表/表格视图
嘿,这个需求我之前帮不少开发者处理过,思路其实挺清晰的,咱们一步步拆解来实现:
核心思路
既然你已经在自定义的QFileSystemModel里维护了选中项的QPersistentModelIndex列表,最靠谱的方案是做一个专门的代理模型,用它过滤出选中的项,再把这个代理模型绑定到你的第二个视图(ListView/TableView)上。这种方式能保证两个视图的数据完全同步,而且性能和可维护性都不错。
具体实现步骤
1. 实现自定义过滤代理模型(C++端)
继承QSortFilterProxyModel,重写filterAcceptsRow方法,只让选中的行通过过滤。同时把选中列表做成可绑定的属性,方便QML同步数据。
#include <QSortFilterProxyModel> #include <QPersistentModelIndex> class SelectedFilesProxyModel : public QSortFilterProxyModel { Q_OBJECT Q_PROPERTY(QList<QPersistentModelIndex> selectedIndexes READ selectedIndexes WRITE setSelectedIndexes NOTIFY selectedIndexesChanged) public: explicit SelectedFilesProxyModel(QObject *parent = nullptr) : QSortFilterProxyModel(parent) {} QList<QPersistentModelIndex> selectedIndexes() const { return m_selectedIndexes; } void setSelectedIndexes(const QList<QPersistentModelIndex> &indexes) { if (m_selectedIndexes != indexes) { m_selectedIndexes = indexes; invalidateFilter(); // 触发过滤规则刷新 emit selectedIndexesChanged(); } } protected: bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override { // 获取原模型对应的索引,判断是否在选中列表里 QModelIndex sourceIndex = sourceModel()->index(source_row, 0, source_parent); return m_selectedIndexes.contains(QPersistentModelIndex(sourceIndex)); } private: QList<QPersistentModelIndex> m_selectedIndexes; signals: void selectedIndexesChanged(); };
记得在main.cpp里把这个模型注册到QML环境:
qmlRegisterType<SelectedFilesProxyModel>("com.your.models", 1, 0, "SelectedFilesProxyModel");
2. QML中绑定模型并展示
在QML里把代理模型和你的自定义QFileSystemModel关联起来,然后用第二个视图绑定代理模型就行。这里以ListView为例:
import QtQuick 2.15 import QtQuick.Controls 2.15 import com.your.models 1.0 Window { width: 900 height: 600 Row { width: parent.width height: parent.height // 原TreeView(保持你原来的配置) TreeView { id: fileTree width: parent.width / 2 height: parent.height model: customFileModel // ... 你的复选框绑定、列配置等原有代码 } // 展示选中项的ListView ListView { width: parent.width / 2 height: parent.height model: selectedProxy delegate: Item { width: parent.width height: 40 Text { anchors.centerIn: parent text: model.fileName // 展示文件名,也可以换成filePath等其他属性 } // 如果要支持在ListView里取消选中,加个复选框绑定原模型的选中Role CheckBox { anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter checked: model.customSelectedRole // 替换成你自定义的选中Role名称 } } } } // 你的自定义QFileSystemModel实例 YourCustomFileSystemModel { id: customFileModel // ... 你的模型初始化配置 } // 代理模型,关联原模型和选中列表 SelectedFilesProxyModel { id: selectedProxy sourceModel: customFileModel selectedIndexes: customFileModel.selectedIndexes // 绑定原模型的选中列表属性 } }
3. 保证选中状态的同步更新
在你的自定义QFileSystemModel里,修改选中状态时要及时更新selectedIndexes列表并发出信号,这样代理模型才能立刻刷新过滤结果。比如:
void YourCustomFileSystemModel::toggleItemSelection(const QModelIndex &index) { bool currentState = data(index, CustomSelectedRole).toBool(); // 更新选中状态 setData(index, !currentState, CustomSelectedRole); QPersistentModelIndex persistentIdx(index); if (!currentState) { m_selectedIndexes.append(persistentIdx); } else { m_selectedIndexes.removeOne(persistentIdx); } // 发出信号通知QML绑定更新 emit selectedIndexesChanged(); }
额外优化提示
- 如果选中项数量很大或者频繁变化,可以在代理模型里做个哈希缓存,把
QPersistentModelIndex存到QSet里,这样判断是否选中的效率会更高。 - 如果用TableView展示,只需要把ListView换成TableView,配置对应的
TableViewColumn即可,代理模型完全通用。 - 要是想支持选中项的排序,代理模型本身就支持排序,直接调用
sort()方法或者在QML里设置sortIndicator就行。
内容的提问来源于stack exchange,提问作者maxwell
相关产品推荐
相关产品推荐

