在没有 "not responding" 的情况下在 QListView 中添加许多数据

Adding many data in QListView without "not responding"

对于一个项目,我需要在一个QListView中集成大量数据,我从一个QThread中获取数据并将其存储在一个QMap中,直到那时我才没有崩溃或冻结的问题。但是当我在我的 QThread 中浏览我的 QMap 来为每个元素调用将在 QListView 中添加 QString 的函数时,我就会冻结。我搜索了很多,但我没有找到或不明白该怎么做。我添加了一部分简化代码来向您展示我的问题:

exemple.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QPushButton>
#include <QListView>
#include <QStandardItemModel>
#include <QDebug>
#include <QThread>

#include "mythread.h"

class exemple : public QMainWindow
{
    Q_OBJECT
public:
    explicit exemple(QWidget *parent = nullptr);

private:
    QPushButton *btn_start;
    QListView *lv_file;
    QMap<QString, QString> myMap;
    MyThread *m_thread;
    QStandardItemModel *model;

public slots:
    void addFileInformation(QString, QString);
    void startShow();

private slots:
    void startThread();

};

#endif // MAINWINDOW_H

mythread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>
#include <QDebug>
#include <QDirIterator>

class MyThread : public QThread
{
    Q_OBJECT
public:
    explicit MyThread(QObject *parent);
    void run();

signals:
    void addFileInformation(QString, QString);
    void startShow();

};

#endif // MYTHREAD_H

exemple.cpp

#include "exemple.h"

exemple::exemple(QWidget *parent) : QMainWindow(parent)
{
    setFixedSize(750,750);

    btn_start = new QPushButton("start", this);
    btn_start->setGeometry(50, 40, 150, 30);
    btn_start->setCursor(Qt::PointingHandCursor);

    lv_file = new QListView(this);
    lv_file->setGeometry(50, 100, 600, 500);

    m_thread = new MyThread(this);
    model = new QStandardItemModel(this);

    lv_file->setModel(model);

    connect(btn_start, SIGNAL(clicked()), this, SLOT(startThread()));
    connect(m_thread, SIGNAL(addFileInformation(QString, QString)),this, SLOT(addFileInformation(QString, QString)));
    connect(m_thread, SIGNAL(startShow()),this, SLOT(startShow()));
}

void exemple::startThread(){
    m_thread->start();
}

void exemple::addFileInformation(QString param1, QString param2)
{
    myMap.insert(param1, param2);
}

void exemple::startShow(){

    for (int i = 0; i < myMap.size(); i++){
        model->appendRow(new QStandardItem(myMap.keys()[i]));
    }
}

在此示例中,当线程调用 startShow 插槽时,我的冻结就会出现。

我知道我不在线程中了,这就是冻结的原因,但是如果我没有像这里那样向 QMap 中的“示例”添加信息,而是 addFileInformation 插槽,我会遇到同样的问题example.cpp直接显示信息。像这样:

exemple.cpp

void exemple::addFileInformation(QString param1, QString param2)
{
    model->appendRow(new QStandardItem(param1));
}

如果您有解决方案、轨道或 link 可以在不冻结的情况下执行此操作,我很感兴趣:)

如果我不清楚,请不要犹豫,让我再次解释,感谢那些愿意花时间帮助我的人。

您可以尝试从视图中取消设置模型 lv_file->setModel(nullptr); 以消除不必要的视图刷新(在每行插入之后),更改模型并将其设置回视图。

如果您的数据集很大,您可能需要实现自己的模型,以您存储数据的方式使用数据。 Qt 中的模型很棘手,但是一旦你完成了一些,它们就会变得有意义。

我在 github 上有一个示例:https://github.com/jplflyer/qt-TreeViewDemo。它可能并不完美。我一边写一边想着怎么写。这是针对 QTreeView,但 QListView 不会有太大不同。

我这里还有一个通用版本:https://github.com/jplflyer/Git-Dashboard。向下查看 GenericItemModel 的树。这是一个模板,实际上有点酷。它也可能不完整,但可能会有所帮助。

您必须使用信号将您的地图数据发送到 ui 线程并在您的线程中追加一行,而不是直接在您的线程中追加一行。

我仔细检查了你的代码,也许你应该试试这个方法:

void exemple::startShow()

    { 
    QList<QStandardItem*> itemList; 
    for (int i = 0; i < myMap.size(); i++)
    { itemList<<(new QStandardItem(myMap.keys()[i])); 
    } 
    model->appendRow(itemList); 
    }