C++ Qml TableView:滚动时崩溃

C++ Qml TableView:滚动时崩溃,c++,windows,qt,qml,tableview,C++,Windows,Qt,Qml,Tableview,我的目标是实现一种具有高速数据更新的模拟器。 该应用程序由以下部分组成: 数据模型:它存储数据,并被TableView用作模型 模拟器:每250ms更新整个数据模型的线程 Qml视图:包含用于显示数据的TableView 一旦启动应用程序,我就可以看到TableView中的数据发生了变化,但是如果我尝试使用鼠标滚轮滚动TableView(保持滚动一段时间),就会出现wierd崩溃 我得到的唯一日志如下: QList::at:“索引超出范围”,文件C:\work\build\qt5\u wor

我的目标是实现一种具有高速数据更新的模拟器。
该应用程序由以下部分组成:

  • 数据模型:它存储数据,并被TableView用作模型
  • 模拟器:每250ms更新整个数据模型的线程
  • Qml视图:包含用于显示数据的TableView
一旦启动应用程序,我就可以看到TableView中的数据发生了变化,但是如果我尝试使用鼠标滚轮滚动TableView(保持滚动一段时间),就会出现wierd崩溃
我得到的唯一日志如下:

QList::at:“索引超出范围”,文件C:\work\build\qt5\u workdir\w\s\qtbase\include/QtCore/./../src/corelib/tools/QList.h,第510行,断言失败

更有趣的是,我只有在Windows环境下才会发生这种崩溃,而在CentOs机器上我没有收到任何错误

我在这里试图提取我的项目的主要部分,并尽可能地概括它。
请查找下面的代码,或者如果您愿意,您可以从

mydata.h

#ifndef MYDATA_H
#define MYDATA_H

#include <QObject>

class MyData : public QObject
{
    Q_OBJECT
    Q_PROPERTY(int first READ first WRITE setFirst NOTIFY firstChanged)
    Q_PROPERTY(int second READ second WRITE setSecond NOTIFY secondChanged)
    Q_PROPERTY(int third READ third WRITE setThird NOTIFY thirdChanged)

public:

    explicit MyData(int first, int second, int third, QObject* parent=0);

    int first()const {return m_first;}
    int second()const {return m_second;}
    int third()const {return m_third;}

    void setFirst(int v){m_first=v;}
    void setSecond(int v){m_second=v;}
    void setThird(int v){m_third=v;}

signals:
    void firstChanged();
    void secondChanged();
    void thirdChanged();

private:
    int m_first;
    int m_second;
    int m_third;
};

#endif // MYDATA_H
#ifndef DATAMODEL_H
#define DATAMODEL_H

#include <QAbstractListModel>
#include <QMutex>
#include "mydata.h"


class DataModel: public QAbstractListModel
{
    Q_OBJECT
public:

    enum DataModelRoles {
        FirstRole = Qt::UserRole + 1,
        SecondRole,
        ThirdRole
    };

    //*****************************************/
    //Singleton implementation:
    static DataModel& getInstance()
            {
                static DataModel    instance; // Guaranteed to be destroyed.
                                      // Instantiated on first use.
                return instance;
            }

    DataModel(DataModel const&) = delete;
    void operator=(DataModel const&)  = delete;
    //*****************************************/

    QList<MyData*>& getData(){return m_data;}

    void addData(MyData* track);

    int rowCount(const QModelIndex & parent = QModelIndex()) const;

    QVariant data(const QModelIndex & index, int role = FirstRole) const;

protected:
    QHash<int, QByteArray> roleNames() const;

private:

    QMutex m_mutex;
    QList<MyData*> m_data;

    DataModel(QObject* parent=0);


};

#endif // DATAMODEL_H
#ifndef SIMULATOR_H
#define SIMULATOR_H

#include <QThread>

class Simulator: public QThread
{
    Q_OBJECT
public:
    Simulator(QObject* parent=0);
    void run() Q_DECL_OVERRIDE;

private:
    void createNewData();
    void updateExistingData();

    int randInt(int from, int to);
};

#endif // SIMULATOR_H
datamodel.h

#ifndef MYDATA_H
#define MYDATA_H

#include <QObject>

class MyData : public QObject
{
    Q_OBJECT
    Q_PROPERTY(int first READ first WRITE setFirst NOTIFY firstChanged)
    Q_PROPERTY(int second READ second WRITE setSecond NOTIFY secondChanged)
    Q_PROPERTY(int third READ third WRITE setThird NOTIFY thirdChanged)

public:

    explicit MyData(int first, int second, int third, QObject* parent=0);

    int first()const {return m_first;}
    int second()const {return m_second;}
    int third()const {return m_third;}

    void setFirst(int v){m_first=v;}
    void setSecond(int v){m_second=v;}
    void setThird(int v){m_third=v;}

signals:
    void firstChanged();
    void secondChanged();
    void thirdChanged();

private:
    int m_first;
    int m_second;
    int m_third;
};

#endif // MYDATA_H
#ifndef DATAMODEL_H
#define DATAMODEL_H

#include <QAbstractListModel>
#include <QMutex>
#include "mydata.h"


class DataModel: public QAbstractListModel
{
    Q_OBJECT
public:

    enum DataModelRoles {
        FirstRole = Qt::UserRole + 1,
        SecondRole,
        ThirdRole
    };

    //*****************************************/
    //Singleton implementation:
    static DataModel& getInstance()
            {
                static DataModel    instance; // Guaranteed to be destroyed.
                                      // Instantiated on first use.
                return instance;
            }

    DataModel(DataModel const&) = delete;
    void operator=(DataModel const&)  = delete;
    //*****************************************/

    QList<MyData*>& getData(){return m_data;}

    void addData(MyData* track);

    int rowCount(const QModelIndex & parent = QModelIndex()) const;

    QVariant data(const QModelIndex & index, int role = FirstRole) const;

protected:
    QHash<int, QByteArray> roleNames() const;

private:

    QMutex m_mutex;
    QList<MyData*> m_data;

    DataModel(QObject* parent=0);


};

#endif // DATAMODEL_H
#ifndef SIMULATOR_H
#define SIMULATOR_H

#include <QThread>

class Simulator: public QThread
{
    Q_OBJECT
public:
    Simulator(QObject* parent=0);
    void run() Q_DECL_OVERRIDE;

private:
    void createNewData();
    void updateExistingData();

    int randInt(int from, int to);
};

#endif // SIMULATOR_H

我很高兴与大家分享我自己答案的解决方案,希望它能帮助那些犯同样错误的人

问题的关键在于:

void Simulator::updateExistingData()
{
    QList<MyData*> list=DataModel::getInstance().getData();
    for(int i=0;i<list.size();i++)
    {
        MyData* curr=list.at(i);
        curr->setSecond(curr->second()+1);
        curr->setThird(curr->third()+2);
        QModelIndex index=DataModel::getInstance().index(i,0, QModelIndex());
        emit DataModel::getInstance().dataChanged(index,index);    //ERROR!
    }
}
在datamodel.cpp中:

public slots:
    void updateGui(int rowIndex);
void DataModel::updateGui(int rowIndex)
{
    QModelIndex qIndex=index(rowIndex,0, QModelIndex());
    dataChanged(qIndex,qIndex);
}
signals:
    void dataUpdated(int row);
Simulator::Simulator(QObject* parent) : QThread(parent)
{
    createNewData();
    connect(this,SIGNAL(dataUpdated(int)), &DataModel::getInstance(), SLOT(updateGui(int)));
}

...

void Simulator::updateExistingData()
{
    QList<MyData*> list=DataModel::getInstance().getData();
    for(int i=0;i<list.size();i++)
    {
        MyData* curr=list.at(i);
        curr->setSecond(curr->second()+1);
        curr->setThird(curr->third()+2);
        QModelIndex index=DataModel::getInstance().index(i,0, QModelIndex());
        emit dataUpdated(i);
    }
}
在模拟器.h中:

public slots:
    void updateGui(int rowIndex);
void DataModel::updateGui(int rowIndex)
{
    QModelIndex qIndex=index(rowIndex,0, QModelIndex());
    dataChanged(qIndex,qIndex);
}
signals:
    void dataUpdated(int row);
Simulator::Simulator(QObject* parent) : QThread(parent)
{
    createNewData();
    connect(this,SIGNAL(dataUpdated(int)), &DataModel::getInstance(), SLOT(updateGui(int)));
}

...

void Simulator::updateExistingData()
{
    QList<MyData*> list=DataModel::getInstance().getData();
    for(int i=0;i<list.size();i++)
    {
        MyData* curr=list.at(i);
        curr->setSecond(curr->second()+1);
        curr->setThird(curr->third()+2);
        QModelIndex index=DataModel::getInstance().index(i,0, QModelIndex());
        emit dataUpdated(i);
    }
}
在模拟器.cpp中:

public slots:
    void updateGui(int rowIndex);
void DataModel::updateGui(int rowIndex)
{
    QModelIndex qIndex=index(rowIndex,0, QModelIndex());
    dataChanged(qIndex,qIndex);
}
signals:
    void dataUpdated(int row);
Simulator::Simulator(QObject* parent) : QThread(parent)
{
    createNewData();
    connect(this,SIGNAL(dataUpdated(int)), &DataModel::getInstance(), SLOT(updateGui(int)));
}

...

void Simulator::updateExistingData()
{
    QList<MyData*> list=DataModel::getInstance().getData();
    for(int i=0;i<list.size();i++)
    {
        MyData* curr=list.at(i);
        curr->setSecond(curr->second()+1);
        curr->setThird(curr->third()+2);
        QModelIndex index=DataModel::getInstance().index(i,0, QModelIndex());
        emit dataUpdated(i);
    }
}
Simulator::Simulator(QObject*parent):QThread(parent)
{
createNewData();
连接(this,SIGNAL(dataUpdated(int)),&DataModel::getInstance(),SLOT(updateGui(int));
}
...
void模拟器::updateExistingData()
{
QList=DataModel::getInstance().getData();
对于(int i=0;isetSecond(curr->second()+1);
curr->setThird(curr->third()+2);
QModelIndex index=DataModel::getInstance().index(i,0,QModelIndex());
发出数据更新(i);
}
}
使用Signal/Slot方法,我们确信请求将由创建该类的线程(Gui线程)在receiver类中处理,因此下面的dataChanged信号将由适当的线程发出