You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

启用排序后QTreeWidget遍历顶层项性能骤降求助

QTreeWidget启用排序后过滤性能暴跌的解决方案

问题根源

启用setSortingEnabled(true)后,QTreeWidget内部会维护一个排序后的项索引映射结构。此时调用topLevelItem(i)会触发索引到实际项的查找开销,而调用setHidden()时,视图会因为项状态变化重新校验排序后的列表,100万条数据下这些操作的累积开销会被放大到数分钟级别——这就是性能骤降的核心原因。

可行优化方案

方案1:临时移除项后再执行过滤

通过将所有项从视图中临时移除,绕过QTreeWidget的排序索引维护逻辑,过滤完成后重新添加项并恢复排序状态:

// 保存当前排序状态
const bool wasSortingEnabled = isSortingEnabled();
setSortingEnabled(false);

// 批量移除所有顶层项
QList<QTreeWidgetItem*> topItems;
while (QTreeWidgetItem* item = invisibleRootItem()->takeChild(0)) {
    topItems.append(item);
}

// 执行过滤逻辑
for (QTreeWidgetItem* pItem : topItems) {
    bool hide = false;
    for (const auto& filter : mFilters) {
        if (hide) break;
        hide = filter.checkFilter(pItem);
    }
    pItem->setHidden(hide);
}

// 重新添加所有项
for (QTreeWidgetItem* item : topItems) {
    invisibleRootItem()->addChild(item);
}

// 恢复排序
if (wasSortingEnabled) {
    setSortingEnabled(true);
    // 保持之前的排序规则
    sortItems(sortColumn(), sortOrder());
}

这种方式下,项不在视图中时调用setHidden()不会触发任何排序相关的内部更新,过滤操作的耗时会回到接近未启用排序时的水平。

方案2:改用QTreeView + QSortFilterProxyModel架构

QTreeWidget是封装好的组件,在大数据量场景下灵活性不足。改用QTreeView+QStandardItemModel+自定义QSortFilterProxyModel的组合,将过滤和排序逻辑交给模型层处理,从根本上优化性能:

  1. 实现自定义过滤代理模型:
#include <QSortFilterProxyModel>
#include <QStandardItemModel>

class CustomFilterProxy : public QSortFilterProxyModel {
public:
    explicit CustomFilterProxy(QObject* parent = nullptr) : QSortFilterProxyModel(parent) {}

    // 注入你的过滤器集合
    void setFilters(const QList<YourFilterType>& filters) {
        m_filters = filters;
        invalidateFilter(); // 触发过滤更新
    }

protected:
    bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override {
        QStandardItemModel* sourceModel = qobject_cast<QStandardItemModel*>(this->sourceModel());
        QStandardItem* item = sourceModel->itemFromIndex(sourceModel->index(sourceRow, 0, sourceParent));
        
        // 应用过滤规则
        bool accept = true;
        for (const auto& filter : m_filters) {
            if (filter.checkFilter(item)) { // 假设checkFilter返回true表示需要隐藏
                accept = false;
                break;
            }
        }
        return accept;
    }

private:
    QList<YourFilterType> m_filters;
};
  1. 替换原QTreeWidget的使用方式:
// 初始化模型和视图
QStandardItemModel* sourceModel = new QStandardItemModel(this);
// 向sourceModel中添加你的100万条数据...

CustomFilterProxy* proxyModel = new CustomFilterProxy(this);
proxyModel->setSourceModel(sourceModel);

QTreeView* treeView = new QTreeView(this);
treeView->setModel(proxyModel);
treeView->setSortingEnabled(true);

// 当需要更新过滤规则时
proxyModel->setFilters(mFilters);

这种方案的优势在于:过滤和排序由专门的代理模型高效处理,视图只渲染符合条件的项,无需手动遍历设置hidden,大数据量下的性能表现远优于QTreeWidget的手动过滤。

为什么你之前的优化无效

你尝试的遍历原始列表、关闭排序等操作,都没有避开QTreeWidget在启用排序后维护的索引映射——只要项还在视图中,调用setHidden()就会触发视图的内部校验逻辑,累积的开销依然巨大。只有彻底断开项与视图的绑定(方案1),或者改用模型层处理过滤(方案2),才能解决问题。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 22:25:23