_S_Q 2023-09-25 14:48 采纳率: 100%
浏览 45
已结题

Qt C++,QTreeView加载大量数据时界面卡顿怎么办?

Qt C++,QTreeView加载大量数据时界面卡顿怎么办?
代码:

    // 说明:1.下面这段代码运行再主线程中

    // class TreeModel : public QAbstractItemModel
    mModel = new TreeModel();
    // 返回根节点
    TreeItem* root = mModel->root();
    // 遍历QList<CYCLE*> mCycles
    for (int i = 0; i < mParser->mCycles.size(); i++)
    {
        CYCLE* c = mParser->mCycles.at(i);
        TreeItem* item1 = new TreeItem(root);
        // 1级节点
        item1->setLevel(1);
        root->appendChild(item1);
        for (int j = 0; j < c->steps.size(); j++)
        {
            STEP* s = c->steps.at(j);
            TreeItem* item2 = new TreeItem(item1);
            //  2级节点
            item2->setLevel(2);
            item1->appendChild(item2);
            const int nRecordsSize = s->records.size();
            for (int k = 0; k < nRecordsSize; k++)
            {
                // 3级节点,该节点约有2千万个,导致界面加载卡顿
                TreeItem* item3 = new TreeItem(item2);
                item2->appendChild(item3);
            }
        }
    }
  • 写回答

2条回答 默认 最新

  • 山南1109 移动开发领域新星创作者 2023-09-25 15:08
    关注

    您好!对于 QTreeView 加载界面不流畅的问题,可能有几个原因导致,请您检查以下几点:

    数据加载速度较慢:查看您的数据加载代码是否存在性能瓶颈。如果您加载的数据量很大,可能需要对数据加载进行优化。例如,您可以考虑使用异步加载或分批加载数据,以减少界面卡顿的现象。

    代码优化:检查您的代码是否存在效率低下的部分。使用合适的数据结构和算法,以及避免无谓的计算等,可以提高界面加载的速度和流畅度。

    硬件资源不足:如果您的计算机硬件资源有限,如处理器和内存等,可能会导致界面加载缓慢。尝试升级硬件或优化资源的使用,以提升性能。

    具体参考方案1:

    使用QAbstractItemModel的子类来管理数据。QAbstractItemModel是Qt中的一个抽象类,它提供了对数据模型的访问和操作。通过自定义的数据模型,可以优化数据的加载和显示。

    使用多线程加载数据。将数据加载的过程放到一个单独的线程中,可以避免阻塞主线程,从而提高界面的流畅性。可以使用Qt提供的QThread类或者QtConcurrent来实现多线程。

    使用分页加载数据。不要一次性将所有数据加载到QTreeView中,而是根据需要逐页加载数据。可以通过监听QAbstractItemModel的dataChanged信号来触发加载下一页数据。

    对于特别大的数据集,可以考虑使用虚拟模型(Virtual Model)来避免一次性加载所有数据。虚拟模型只在需要显示时加载相应的数据,以减少内存占用和提高性能。
    根据您提供的代码,您的问题在于创建具有大量(约2千万个)第三级节点的树视图(QTreeView)时,导致界面加载卡顿。这可能是由于创建和添加大量节点导致的性能问题。

    具体优化方案2:

    异步加载:考虑使用异步加载机制,以避免界面被大量节点卡住。您可以使用QRunnable、QThreadPool等来进行异步加载节点的操作,以便在节点加载完成后再将其添加到树视图中。

    分批加载:不要一次性加载全部节点。可以通过分批加载节点的方式,逐步显示节点,从而减轻界面卡顿问题。例如,在视图上只显示可见节点及其一部分的子节点,而延迟加载其他子节点。

    虚拟化和缓存:考虑使用虚拟化和缓存技术来优化树视图的性能。通过只创建和显示可见节点,而不是全部节点,可以大大减少内存使用和界面加载时间。

    优化数据结构:检查您的数据结构是否适合快速访问和操作。如果需要频繁的查找和修改节点,可能需要考虑使用更适合的数据结构,例如哈希表或平衡二叉树。
    下面是一个优化后的代码示例,其中使用了分批加载和异步加载的方法来优化树视图的性能:

    // class TreeModel : public QAbstractItemModel
    mModel = new TreeModel();
    // 返回根节点
    TreeItem* root = mModel->root();
    // 遍历 QList<CYCLE*> mCycles
    for (int i = 0; i < mParser->mCycles.size(); i++)
    {
        CYCLE* c = mParser->mCycles.at(i);
        TreeItem* item1 = new TreeItem(root);
        // 1级节点
        item1->setLevel(1);
        root->appendChild(item1);
        
        // 通过异步加载方式加载第二级节点及以下的节点
        QThreadPool::globalInstance()->start(new LoadTreeItemTask(item1, c->steps));
    }
    

    在上述代码中,我们使用了名为LoadTreeItemTask的自定义任务类来异步加载节点。这个任务类负责加载给定级别节点以下的所有节点。下面是LoadTreeItemTask类的示例代码:

    class LoadTreeItemTask : public QRunnable
    {
    public:
        LoadTreeItemTask(TreeItem* parentItem, const QList<STEP*>& steps)
            : mParentItem(parentItem), mSteps(steps) {}
     
        void run() override
        {
            for (int j = 0; j < mSteps.size(); j++)
            {
                STEP* s = mSteps.at(j);
     
                // 分批加载子节点
                const int batchSize = 100; // 每批加载100个节点
                for (int k = 0; k < s->records.size(); k += batchSize)
                {
                    const int endIndex = qMin(k + batchSize, s->records.size());
                    for (int index = k; index < endIndex; index++)
                    {
                        // 创建并添加第三级节点
                        TreeItem* item3 = new TreeItem(mParentItem);
                        mParentItem->appendChild(item3);
                    }
     
                    // 发送更新信号,让UI进行刷新显示可见节点的改变
                    emit updateUI();
                }
            }
        }
     
    signals:
        void updateUI();
     
    private:
        TreeItem* mParentItem;
        QList<STEP*> mSteps;
    };
    

    在上述代码中,LoadTreeItemTask类在异步线程中执行,并逐批加载第三级节点。每一批次加载完成后,通过发送更新信号,通知UI刷新可见节点的显示。

    请根据您自己的代码结构和需求进行适当调整和改进。这个示例代码能够通过分批加载和异步加载来优化树视图的性能,避免界面卡顿,并提高加载速度。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 9月25日
  • 已采纳回答 9月25日
  • 创建了问题 9月25日

悬赏问题

  • ¥15 ansys fluent计算闪退
  • ¥15 有关wireshark抓包的问题
  • ¥15 需要写计算过程,不要写代码,求解答,数据都在图上
  • ¥15 向数据表用newid方式插入GUID问题
  • ¥15 multisim电路设计
  • ¥20 用keil,写代码解决两个问题,用库函数
  • ¥50 ID中开关量采样信号通道、以及程序流程的设计
  • ¥15 U-Mamba/nnunetv2固定随机数种子
  • ¥15 vba使用jmail发送邮件正文里面怎么加图片
  • ¥15 vb6.0如何向数据库中添加自动生成的字段数据。