2016-04-08 9 views
0

私の目標は、高速のデータ更新を伴う一種のシミュレータを実装することです。
アプリケーションは、以下の部分から構成されている:
Qml TableView:スクロール中にクラッシュする

  • データモデル:これは、データを格納し、それがシミュレータモデル
  • としてテーブルビューで使用される:全データ・モデルを更新スレッド250msごと
  • A QMLビュー:私は、アプリケーションを起動すると、私はテーブルビューに変更したデータを見ることができるとすぐにデータ

を表示するテーブルビューが含まれていますが、私がしようとする奇妙なクラッシュがありますTableViをスクロールするマウスホイールを使ってewします(しばらくスクロールし続けます)。
以下れる私が得る唯一のログに:QListの中

ASSERTに失敗::で: "範囲外のインデックス"、ファイルC:\作業\ビルド\ qt5_workdir \ \ sの\ qtbase \ wを含んで/QtCore/../../src/corelib/tools/qlist.h、ライン510

より興味深いのは、CentOSのマシンに私がいる間、私は、Windows環境でのみ、このクラッシュを取得するということですエラーは発生しません。

私はここでプロジェクトの主要部分を抽出し、可能な限り一般化しようとしました。
コードの下に検索、またはあなたが好む場合はthis link

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 

mydata.cpp

#include "mydata.h" 

MyData::MyData(int first, int second, int third, QObject* parent) : QObject(parent) 
{ 
    m_first=first; 
    m_second=second; 
    m_third=third; 
} 

datamodel.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 

datamodel.cpp

#include "DataModel.h" 
#include "QDebug" 

DataModel::DataModel(QObject* parent): QAbstractListModel(parent) 
{ 

} 

void DataModel::addData(MyData *track) 
{ 
    beginInsertRows(QModelIndex(),rowCount(),rowCount()); 
    m_data<<track; 
    endInsertRows(); 
} 

int DataModel::rowCount(const QModelIndex &parent) const 
{ 
    Q_UNUSED(parent) 
    return m_data.size(); 
} 

QVariant DataModel::data(const QModelIndex &index, int role) const 
{ 
    MyData* data=m_data[index.row()]; 
    switch (role) { 
    case FirstRole: 
     return data->first(); 

    case SecondRole: 
     return data->second(); 

    case ThirdRole: 
     return data->third(); 
    default: 
     return QVariant(); 
    } 
} 



QHash<int, QByteArray> DataModel::roleNames() const 
{ 
    QHash<int, QByteArray> roles; 
    roles[FirstRole] = "First"; 
    roles[SecondRole] = "Second"; 
    roles[ThirdRole] = "Third"; 
    return roles; 
} 

simulator.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 

simulator.cpp

#include "simulator.h" 
#include <math.h> 
#include <mydata.h> 
#include <datamodel.h> 
Simulator::Simulator(QObject* parent) : QThread(parent) 
{ 
    createNewData(); 
} 

void Simulator::run() 
{ 
    long updateRate=250; 
    while(true) 
    { 
     updateExistingData(); 
     msleep(updateRate); 
    } 
} 


void Simulator::createNewData() 
{ 
    int numOfData=10000; 
    for(int i=0;i<numOfData;i++) 
    { 
     int first=i; 
     int second=randInt(0,1000); 
     int third=randInt(0,1000); 
     MyData* data=new MyData(first,second,third); 
     DataModel::getInstance().addData(data); 
    } 

} 

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);  
    } 
} 

int Simulator::randInt(int from, int to) 
{ 
    // Random number between from and to 
    return qrand() % ((to + 1) - from) + from; 
} 

main.cppに

#include <QGuiApplication> 
#include <QQmlApplicationEngine> 
#include "simulator.h" 
#include "datamodel.h" 
#include <QQmlContext> 

int main(int argc, char *argv[]) 
{ 
    QGuiApplication app(argc, argv); 

    DataModel& model=DataModel::getInstance(); 

    Simulator* s=new Simulator(); 
    s->start(); 

    QQmlApplicationEngine engine; 

    QQmlContext *ctxt = engine.rootContext(); 
    ctxt->setContextProperty("myModel", &model); 

    engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); 

    return app.exec(); 
} 

main.qml

import QtQuick 2.5 
import QtQuick.Window 2.2 
import QtQuick.Controls 1.4 
import QtQuick.Layouts 1.1 
import QtQuick.Controls.Styles 1.4 

Window { 
    visible: true 
    width: 800 
    height: 600 

    TableView { 
     id: tableView 
     width: parent.width 
     height: parent.height 
     frameVisible: true 

     model: myModel 
     sortIndicatorVisible: true 
     property string fontName: "Arial" 

     TableViewColumn { 
      id: firstColumn 
      title: "First" 
      role: "First" 
      movable: false 
      resizable: false 
      width: tableView.viewport.width/3 
      delegate: Text{ 
       font.family: tableView.fontName 
       text: styleData.value 
       horizontalAlignment: TextInput.AlignHCenter 
       verticalAlignment: TextInput.AlignVCenter 

      } 
     } 
     TableViewColumn { 
      id: secondColumn 
      title: "Second" 
      role: "Second" 
      movable: false 
      resizable: false 
      width: tableView.viewport.width/3 
      delegate: Text{ 
       font.family: tableView.fontName 
       text: styleData.value 
       horizontalAlignment: TextInput.AlignHCenter 
       verticalAlignment: TextInput.AlignVCenter 

      } 
     } 
     TableViewColumn { 
      id: thirdColumn 
      title: "Third" 
      role: "Third" 
      movable: false 
      resizable: false 
      width: tableView.viewport.width/3 
      delegate: Text{ 
       font.family: tableView.fontName 
       text: styleData.value 
       horizontalAlignment: TextInput.AlignHCenter 
       verticalAlignment: TextInput.AlignVCenter 

      } 
     } 
    } 
} 

答えて

0

は、私はそれは同じエラーを取得している人を助けることができる期待して、あなたと私自身の答えに解決策を共有することをうれしく思います。

問題の重要な点はここにある:私はGUIスレッドではないスレッドでのDataModelに信号を発するのです実際に

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! 
    } 
} 

:これは間、同時アクセスの問題に分類されます(TableViewを満たすためにデータにアクセスしている)GUIスレッドと(値を更新するためにデータにアクセスしている)アップデータスレッドを使用します。

解決策は、guiスレッド上でdataChanged信号を出力することです.Qt信号/スロットメカニズムを使用することでそれを行うことができます。
したがって:
datamodel.h において:

public slots: 
    void updateGui(int rowIndex); 

datamodel.cpp において:

simulator.hにおいて:

signals: 
    void dataUpdated(int row); 

simulator.cpp で:

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); 
    } 
} 

シグナル/スロットのアプローチを使用して、我々はそのため、要求はそのクラス(GUIスレッド)を作成したスレッドによって受信機クラスで処理されると確信しています次のdataChanged信号が適切なスレッドによって送出されます。

関連する問題