Hi, i'm trying to sort a QtableView's column containing numbers, using QSortFilterProxyModel::sort(), but is veeery slow. It's ok sorting strings, good speed, but horrible with numbers.
Any way to solve this please?
Thanks.
Hi, i'm trying to sort a QtableView's column containing numbers, using QSortFilterProxyModel::sort(), but is veeery slow. It's ok sorting strings, good speed, but horrible with numbers.
Any way to solve this please?
Thanks.
Its a very simple code:
First i connect the QTableView header to the slot:
Qt Code:
connect(gameView->horizontalHeader(), SIGNAL(sectionClicked(int)), this, SLOT(saveSortOrder(int)));To copy to clipboard, switch view to plain text mode
and this is the slot at this moment:
Takes about 5 seconds to sort a table with 1.864 rows.Qt Code:
void RetroGC::saveSortOrder(int ind) { romProxy->sort(ind, Qt::AscendingOrder); // gameView->horizontalHeader()->setSortIndicatorShown(true); // QSettings sortSettings(QString("Data/SSettings/%1/%2.ini").arg(CurrType).arg(CurrID), QSettings::IniFormat); // sortSettings.setValue( "Sort/Col", ind ); // sortSettings.setValue("Sort/Mode", gameView->horizontalHeader()->sortIndicatorOrder()); }To copy to clipboard, switch view to plain text mode
I've commented some lines for testing. I've tried gameView->sortByColum() and still slow.
EDIT: Ok, after some testings, i've found the problem. Only some rows have a different value because the default value is 0. If i fill the rows with incrementing integers, 1, 2, 3 ,4 ,5... etc., the sort speed its amazing. So, here is the new question: Is there any way to fix this problem? Any way to ignore that rows with the 0 value in that cell?
Last edited by aguayro; 13th December 2012 at 15:22.
What is the source model of the proxy? How is its data() method implemented?
The source model is a reimplemented QAbstractTableModel, beacuse i need lazy population for big (10.000+ rows) tables.
Here is the full data() implementation:
Qt Code:
{ if (!index.isValid()) if (index.row() >= ROMs.size() || index.row() < 0) if (role == Qt::SizeHintRole){ if(index.column() == 2) { } } if (role == Qt::TextAlignmentRole){ if(index.column() == 3) { return Qt::AlignHCenter; } if(index.column() == 4) { return Qt::AlignHCenter; } } if (role == Qt::DecorationRole) { if(index.column() == 2) { } } if (role == Qt::DisplayRole) { if(index.column() == 0) { return ROMi.completeBaseName(); } if(index.column() == 2) { } if(index.column() == 3) { if(!SetEmu.value(QString("%1/Name").arg( SetEmu.value("DefaultEmulator/RGCID").toString()) ).toString().isEmpty()) { return SetEmu.value(QString("%1/Name").arg( SetEmu.value("DefaultEmulator/RGCID").toString()) ).toString(); } } if(index.column() == 4) { // This is the column i'm sorting, all row's value is 0 if the game is not played, so there are a lot of "0" cells slowing the sort } else { return 0; } } if(index.column() == 9) { return ROMs.at(index.row()); } } }To copy to clipboard, switch view to plain text mode
Your data() implementation is quite slow (because of creating and accessing the instance of QSettings), maybe that's what causes sorting to be slow since each item is being accessed multiple times and each time you're creating new QSettings instance. Maybe you should cache those values you can in the model?
aguayro (13th December 2012)
Ok, i'll try to read all the values, or add all values into the game list, with the names, like "Name;played;rating;etc", and use QString::section() instead of QSettings. Probably that will solve the proble, name sorting is very fast, where there is not any QSettings access.
Thanks wysota, you are a life saver again.
The most obvious improvement is to create the settings object just once and keep it opened as a member variable of the model. I can see you're always creating QSettings with the same parameters so keeping the settings object open will at least prevent it from being parsed at each call to data().
I fixed the slow issue, but theres a new problem.
My custom model has a reimplemented setData() :
Qt Code:
if(index.isValid() && role == Qt::DisplayRole ) { if(index.column() == 4) { int row = index.row(); ROMs.replace(row, tmp.join(";")); emit dataChanged(index, index); return true; } else { return false; } } return false; }To copy to clipboard, switch view to plain text mode
All the table data loads from ROMs QstringList, so if i change some cell of column 4, it will be updated, but only works with some cells, some works, some doesn't work, its trange.
Here is the data change:
Qt Code:
qint32 xt = gameList->index(row, 4).data(Qt::DisplayRole).toInt(); xt++; gameList->setData( gameList->index(row, 4), xt, Qt::DisplayRole ); }To copy to clipboard, switch view to plain text mode
i've been 2 hours stucked and investigating, but i can't find where is the problem.
First of all handle EditRole in your setData implementation in addition to DisplayRole. Second of all I suggest you restructure your program. Make it never access any of the ROM data directly without the model. It's better to add methods to the model class that will perform operations on the data itself than to risk modifying the data outside the model. You could simply have a increaseColumn4(const QModelIndex&) method that would bump up the number in the model and emit dataChanged().
But the user will not add nothing manually, all is done by the app, if i use EditRole it seems to nothing happens.
Ok, i'll restructure all the model thing, so all the ROM data will only managed by the model, if i understood crrectly.
thaks again, and sorry my for programming noobness. >.<
Bookmarks