PDA

View Full Version : speed of setdata - lots of items in treeview



Big Duck
5th July 2006, 18:25
Hi all,

I need to populate the standardItemModel for my treeView, with possibly upto 300,000 rows.

My treeView acts like a TableView, I guess I could use TableView if its quicker, as there is a flat hierarchy of items.

At the moment 30,000 rows can take 5-6 seconds, which is unacceptable.
I'm pretty sure I'm doing something sub-optimal.
Thus why the need for a progress bar.

Any suggestions please.




treeView = new QTreeView;
model = new QStandardItemModel(0,13);
treeView->setModel(model);

void GamesTab::showMatches()
{
treeView->setUpdatesEnabled (false);

modelindex = model->index(0, 0, modelindex);
model->insertRows(0, mainBoard->filteredResults.size(), modelindex);
QVariant data;

QString number =
for (unsigned int i = 0; i < mainBoard->filteredResults.size(); i++) {
int db = mainBoard->filteredResults[i]->dbIndex;
int game = mainBoard->filteredResults[i]->gameIndex;
gamePtr = dbManager_->databases[db]->database->Games[game];

data = (dbManager_->databases[db]->name).c_str();
model->setData(model->index(i, headerPosDatabase_, modelindex), data);
data = (gamePtr->getPlayerW()).c_str();
model->setData(model->index(i, headerPosPlayerWhite_, modelindex), data);
data = (gamePtr->getPlayerB()).c_str();
model->setData(model->index(i, headerPosPlayerBlack_, modelindex), data);
data = (gamePtr->getRankW()).c_str();
model->setData(model->index(i, headerPosRankWhite_, modelindex), data);
data = (gamePtr->getRankB()).c_str();
model->setData(model->index(i, headerPosRankBlack_, modelindex), data);
data = (gamePtr->getResultStr()).c_str();
model->setData(model->index(i, headerPosResult_, modelindex), data);
data = (gamePtr->getKomi()).c_str();
model->setData(model->index(i, headerPosKomi_, modelindex), data);
data = (gamePtr->getDate()).c_str();
model->setData(model->index(i, headerPosDate_, modelindex), data);
data = gamePtr->getMoveCount();
model->setData(model->index(i, headerPosMoveCount_, modelindex), data);
data = (gamePtr->getHandicap()).c_str();
model->setData(model->index(i, headerPosHandicap_, modelindex), data);
data = (gamePtr->getPlace()).c_str();
model->setData(model->index(i, headerPosPlace_, modelindex), data);
data = (gamePtr->getEvent()).c_str();
model->setData(model->index(i, headerPosEvent_, modelindex), data);

progressBar_->setValue(i + 1);
}

treeView->setUpdatesEnabled (true);

jacek
5th July 2006, 18:49
At the moment 30,000 rows can take 5-6 seconds, which is unacceptable.
How long does it take when you replace all "(...).c_str()" with some constant string?

Model has to emit appropriate signals each time it is changed, if you would write your own model, you could populate it in one go (without using setData() and emitting signals for each item).


Thus why the need for a progress bar.
While your program updates the model, Qt can't process events, so to make your progress bar work you have to invoke QCoreApplication::processEvents().

Big Duck
5th July 2006, 19:09
I tried using a tableView instead of a TreeView and there was no speed difference.

I tried replacing "(...).c_str()" with some constant string and it makes very little difference to the time, it still is about 5 seconds for 30,000 rows.




Model has to emit appropriate signals each time it is changed, if you would write your own model, you could populate it in one go (without using setData() and emitting signals for each item).


Sounds good to me ! If I dont use setData, how would I go about writing my own Model ? Subclassing StandardItemModel or perhaps AbstarctItemModel ?

Would I implement a function to use SetData within the subclassed model and somehow turn off signals being emitted ?

Thanks for setting me on the right track.

jacek
5th July 2006, 19:40
I tried replacing "(...).c_str()" with some constant string and it makes very little difference to the time, it still is about 5 seconds for 30,000 rows.
So the problem is most likely with setData().


If I dont use setData, how would I go about writing my own Model ? Subclassing StandardItemModel or perhaps AbstarctItemModel ?
IMO the easiest way is to subclass QAbstractTableModel --- there are instructions in the docs how to do it (just don't forget to invoke beginInsertRow() and endInsertRows() when you add rows to your model).

You need setData() only if you want your users to change the model contents using a view. If users only view the data, you don't need it at all.

Few examples:
int SomeModel::rowCount( const QModelIndex& parent ) const
{
if( ! parent.isValid() ) { // someone wants to know the number of rows of top-level items
return _data.size(); // get the number of items in the vector, list or whatever collection you will use
}
else {
return 0; // since we don't have any children (there is only one layer of items in the model)
}
}


QVariant SomeModel::data( const QModelIndex& index,
int role ) const
{
if( index.isValid() ) {

// find the right item

switch( role ) {

case Qt::DisplayRole: // data that should be diplayed in cell (index.row(), index.column())
{
switch( index.column() ) { // or simply: return item.property( index.column() );
case Something:
return item.something();

case SomethingDifferent:
return item.somethingDifferent();

default:
return QVariant();
}
break;
}
// and so on
}
}
return QVariant();
}

Big Duck
6th July 2006, 12:53
Hi, just wanted to say a big thank you for solving this.

It now takes 0 seconds :) to display 30,000 rows in the TableView, by subclassing an AbstractTableModel.
I am now starting to understand the power of a MVC design!

I never thought it would work but wow, its fast.

Below is some code in case it helps someone to do the same:




int ResultsModel::rowCount(const QModelIndex &parent) const
{
filteredResults.size();
}



int ResultsModel::columnCount(const QModelIndex &parent) const
{
return 13;
}




QVariant ResultsModel::data(const QModelIndex &index, int role) const
{

QVariant data;

if (!index.isValid()) {
return QVariant();
}

if (index.row() >= filteredResults.size()) {
return QVariant();
}

if (index.column() >= 13) {
return QVariant();
}

if (role == Qt::DisplayRole) {
int db = mainBoard->filteredResults[index.row()]->dbIndex;
int game = mainBoard->filteredResults[index.row()]->gameIndex;
boost::shared_ptr<Game> gamePtr = mainWindow_->dbManager_->databases[db]->database->Games[game];

switch (index.column()) {
case 0 : {
data = (mainWindow_->dbManager_->databases[db]->name).c_str();
return data;
}
case 1 : {
data = (gamePtr->getPlayerW()).c_str();
return data;
break;
}
case 2 : {
data = (gamePtr->getPlayerB()).c_str();
return data;
break;
}

// ETC ETC

}
}
// else
return QVariant();
}