在没有 "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);
}
对于一个项目,我需要在一个QListView中集成大量数据,我从一个QThread中获取数据并将其存储在一个QMap
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);
}