subclass queryModel
-
Hello,
I want to create my own querymodel class to make some edits to my data model.
However, I am new to this. I created my own model class as below and implemented some functions.
my model class works fine on data with 0 to 200 rows.
But it works a bit slow on data with 1000-2000 rows. How can I optimize this model class to run the fastest?
I am sharing my code with you. Can you tell me my mistakes or where it could be better?For example, I am using a 2D string array as a datasource in the class. Is this method correct?
myModel.h :#define MYMODEL_H #include <QSqlQueryModel> #include <QObject> #include <QSqlRecord> class myModel: public QSqlQueryModel { Q_OBJECT public: explicit myModel(QString **dataList,QStringList headerDataList,QObject *parent = nullptr,int rowcount=0,int colcount=0); public: QVariant data(const QModelIndex &index, int role) const; int rowCount(const QModelIndex &parent) const; int columnCount(const QModelIndex &parent) const; QVariant headerData(int section, Qt::Orientation orientation, int role) const; Qt::ItemFlags flags(const QModelIndex &index) const; private: QSqlQueryModel *_model; QString **_dataList; QStringList _headerDataList; const int _rowCount,_colCount; }; #endif // MYMODEL_HmyModel.cpp :
#include "myModel.h" myModel::myModel(QString **dataList,QStringList headerDataList, QObject *parent,int rowcount,int colcount) : QSqlQueryModel{parent},_dataList(dataList),_headerDataList(headerDataList),_rowCount(rowcount),_colCount(colcount) { } QVariant myModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if(index.row()>_rowCount-1 || index.column()>_colCount-1) return QVariant(); switch (role) { case Qt::DisplayRole: return _dataList[index.row()][index.column()]; case Qt::TextAlignmentRole: return Qt::AlignCenter; } return QVariant(); //return _model->record(index.row()).value(index.column()); } int myModel::rowCount(const QModelIndex &parent) const { //return _model->rowCount(); return _rowCount; } int myModel::columnCount(const QModelIndex &parent) const { //return _model->columnCount(); return _colCount; } QVariant myModel::headerData(int section, Qt::Orientation orientation, int role) const { if(orientation == Qt::Horizontal) { if(role == Qt::DisplayRole) { return _headerDataList.at(section); //return _model->headerData(section,orientation); } } return QVariant(); } Qt::ItemFlags myModel::flags(const QModelIndex &index) const { return QSqlQueryModel::flags(index) |Qt::ItemIsDragEnabled; } -
Hi,
First thing: why are you subclassing QSqlQueryModel when you want to show a custom data structure ? QAbstractTableModel would make more sense.
Then, why not use something likeQVector<QStringList>or evenQVector<QVector<QString>>so you can more easily manipulate your data ? That would also allow you to have row and column count determined by the actual size of your 2D data rather than on fixed values. -
@SGaist said in subclass queryModel:
Hi,
First thing: why are you subclassing QSqlQueryModel when you want to show a custom data structure ? QAbstractTableModel would make more sense.why do you suggest me to use QAbstractTableModel? what is the difference of this ?
Thanks, I'll look into the other things you said. -
QSqlQueryModel is designed to make database access while you do not do that at all.
It's like taking the frame of an SUV to use it as a go-kart.
Use the right tool for your purpose and in your case QAbstractTableModel is the one that makes sense.
-
Hello again,
As you said, I converted the model to QAbstractTableModel and used 2D QVector as source list ( data and header data).
new code :myModel::myModel(QVector<QVector<QString> > *dataList,QVector<QString> headerDataList, QObject *parent,int rowcount,int colcount) : QAbstractTableModel{parent},_dataList(dataList),_headerDataList(headerDataList),_rowCount(rowcount),_colCount(colcount) { } QVariant myModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if(index.row()>_dataList->at(0).count()-1 || index.column()>_dataList->count()-1) return QVariant(); switch (role) { case Qt::DisplayRole: return _dataList->at(index.column()).at(index.row()); case Qt::TextAlignmentRole: return Qt::AlignCenter; } return QVariant(); } int myModel::rowCount(const QModelIndex &parent) const { return _dataList->at(0).count(); } int myModel::columnCount(const QModelIndex &parent) const { return _dataList->count(); } QVariant myModel::headerData(int section, Qt::Orientation orientation, int role) const { if(orientation == Qt::Horizontal) { if(role == Qt::DisplayRole) { return _headerDataList.at(section); } } return QVariant(); }But I'm asking for better speed.
For example, a model with 1000 rows and 15 columns takes a long time to load into these vectors. Is there a more convenient or faster method for this?_dataList = new QVector<QVector<QString> >; QVector<QString> _headerDataList; rowcount = _model->rowCount(); // this _model is another normal QSqlQueryModel. colcount = _model->columnCount(); for(int col = 0; col<colcount; col++) { QVector<QString> columnList; for(int row = 0; row <rowcount ; row++) { columnList.append(_model->data(_model->index(row,col)).toString()); } _dataList->append(columnList); _headerDataList.append(_model->headerData(col,Qt::Horizontal).toString()); } -
Hello again,
As you said, I converted the model to QAbstractTableModel and used 2D QVector as source list ( data and header data).
new code :myModel::myModel(QVector<QVector<QString> > *dataList,QVector<QString> headerDataList, QObject *parent,int rowcount,int colcount) : QAbstractTableModel{parent},_dataList(dataList),_headerDataList(headerDataList),_rowCount(rowcount),_colCount(colcount) { } QVariant myModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if(index.row()>_dataList->at(0).count()-1 || index.column()>_dataList->count()-1) return QVariant(); switch (role) { case Qt::DisplayRole: return _dataList->at(index.column()).at(index.row()); case Qt::TextAlignmentRole: return Qt::AlignCenter; } return QVariant(); } int myModel::rowCount(const QModelIndex &parent) const { return _dataList->at(0).count(); } int myModel::columnCount(const QModelIndex &parent) const { return _dataList->count(); } QVariant myModel::headerData(int section, Qt::Orientation orientation, int role) const { if(orientation == Qt::Horizontal) { if(role == Qt::DisplayRole) { return _headerDataList.at(section); } } return QVariant(); }But I'm asking for better speed.
For example, a model with 1000 rows and 15 columns takes a long time to load into these vectors. Is there a more convenient or faster method for this?_dataList = new QVector<QVector<QString> >; QVector<QString> _headerDataList; rowcount = _model->rowCount(); // this _model is another normal QSqlQueryModel. colcount = _model->columnCount(); for(int col = 0; col<colcount; col++) { QVector<QString> columnList; for(int row = 0; row <rowcount ; row++) { columnList.append(_model->data(_model->index(row,col)).toString()); } _dataList->append(columnList); _headerDataList.append(_model->headerData(col,Qt::Horizontal).toString()); }@Nevez said in subclass queryModel:
For example, a model with 1000 rows and 15 columns takes a long time to load into these vectors. Is there a more convenient or faster method for this?
Define "a long time". It should take "very little" time.
What here is taking much time? If you want fastest, why do you go through your existing model at the
_model->data(_model->index(row,col))level? If you have access to the underlying actual model/data (like your_dataList) you can read from that directly to avoid the model indexing overhead.Nonetheless, I still would not expect your code to take long for "1000 rows and 15 columns".
-
@JonB said in subclass queryModel:
"Uzun bir süre" tanımlayın. "Çok az" zaman almalıdır.
Yes, I should have explained this part a little more. So when I run the project, it loads 1000 rows and 10 columns of data to the _dataList in about 1-2 minutes. ( In the for loop I showed above)
Don't you think it's a long time?@JonB said in subclass queryModel:
If you want fastest, why do you go through your existing model at the _model->data(_model->index(row,col)) level?
what should I do ?
@JonB said in subclass queryModel:
If you have access to the underlying actual model/data (like your _dataList) you can read from that directly to avoid the model indexing overhead.
sorry, i didn't understand completely. Can you show an example from my code?
-
@JonB said in subclass queryModel:
"Uzun bir süre" tanımlayın. "Çok az" zaman almalıdır.
Yes, I should have explained this part a little more. So when I run the project, it loads 1000 rows and 10 columns of data to the _dataList in about 1-2 minutes. ( In the for loop I showed above)
Don't you think it's a long time?@JonB said in subclass queryModel:
If you want fastest, why do you go through your existing model at the _model->data(_model->index(row,col)) level?
what should I do ?
@JonB said in subclass queryModel:
If you have access to the underlying actual model/data (like your _dataList) you can read from that directly to avoid the model indexing overhead.
sorry, i didn't understand completely. Can you show an example from my code?
@Nevez said in subclass queryModel:
So when I run the project, it loads 1000 rows and 10 columns of data to the _dataList in about 1-2 minutes. ( In the for loop I showed above)
It "cannot" take that long to execute those statements 1,000 times so I don't know what to say. Can only suggest you step through in debugger or set up a completely standalone program to do what you show and try there.
sorry, i didn't understand completely. Can you show an example from my code?
For
columnList.append(_model->data(_model->index(row,col)).toString());if you have access to the "datalist" for your dedicated
_modelyou are reading from, something like:columnList.append(_the_model_datalist[col][row]);to avoid going through
_model->data()etc.But now that you have said "minutes" to do the copying loop this should be irrelevant in comparison to that as-yet-unexplained slowness.