[Qt-interest] QTreeView and custom QAbstractItemModel performance problem

Andreas Pakulat apaku at gmx.de
Thu Jul 8 16:35:58 CEST 2010


On 08.07.10 16:09:52, Felix Brack wrote:
> On 08.07.2010 12:50, Andreas Pakulat wrote:
> > On 08.07.10 11:51:38, Felix Brack wrote:
> >> On 08.07.2010 10:58, Andreas Pakulat wrote:
> >>> On 08.07.10 10:14:11, Felix Brack wrote:
> >>>> By subclassing QAbstractItemModel I have create a custom model that
> >>>> stores data from a communication trace row by row. Every row has
> >>>> multiple columns such as a time stamp, the data traced from the
> >>>> communication, etc. The number of rows in the data model is limited,
> >>>> let's say to 100 rows. When adding row 101 it is appended and the first
> >>>> row (i.e. the one with the oldest data) is removed.
> >>>>
> >>>> To show the information to the user I use a QTreeView which shows each
> >>>> row of the data in the model line by line, i.e. the model is not
> >>>> hierarchic, all rows have the same parent (root) and consist of multiple
> >>>> columns.
> >>>>
> >>>> Things are working so far but performance is very poor and the CPU load
> >>>> is incredible (even with just 100 rows). The reason for this is that
> >>>> whenever I append a row to the model the view calls the models 'data'
> >>>> member for all rows and all columns.
> >>>>
> >>>> It seems that I'm missing something fundamental here and that appending
> >>>> a row of data to my model looks for the view like the entire data has
> >>>> changed. I will have to change something so only the data from the newly
> >>>> append row is queried by the view.
> >>>>
> >>>> I just don't know how to do that... Can anybody push me into the right
> >>>> direction?
> >>>
> >>> Can you post your model implementation? It sure sounds like you're doing
> >>> the appending wrong, but without having a look at the code its not possible
> >>> to say what exactly is wrong.
> >>>
> >>> A blind guess could be that you're reset'ting you're model every time you
> >>> add a row instead of using begin/endInsertRows correctly. See the example
> >>> models in Qt.
> >>>
> >>> Also I'd suggest to use a QTableView instead of QTreeView as that one is
> >>> significantly faster on non-tree structures (you can tweak it to have no
> >>> lines etc.) in case you ever get more than 100 rows.
> >>
> >> Hello Andreas,
> >>
> >> Thanks for your response. The code below is my 'AppendRow' method. The
> >> variable 'm_Data' and 'm_IconKey' are just arrays containing the textual
> >> data as well as an icon that gets displayed in the first column.
> >>
> >> QModelIndex CMultiColumnListModel::AppendRow(QString IconKey,
> >> QStringList Data)
> >> {
> >>     beginInsertRows(QModelIndex(), m_Data.size(), m_Data.size()) ;
> >>     m_Data.push_back(Data);
> >>     m_IconKey.push_back(IconKey);
> >>     endInsertRows();
> >>
> >>     if ((m_nMaxRows!=0)&&  ((int)(m_Data.size())>m_nMaxRows)) {
> >>       // remove oldest element from list
> >>       beginRemoveRows(QModelIndex(), 0, 0);
> >>       m_Data.erase(m_Data.begin());
> >>       m_IconKey.erase(m_IconKey.begin());
> >>       endRemoveRows();
> >>     }
> >>
> >>     return index(m_Data.size()-1, 0);
> >> }
> >>
> >> Do you see any problem here?
> >
> > No, can't see anything obvious wrong. Could be the removal of the first
> > element is the culprit. In general the data() function of your model should
> > be as fast as humanly possible using as little computed data and as much
> > pre-computed data as you can get.
> >
> > Andreas
> >
> 
> The removal operation in my AppendRow() function is only executed when 
> there are more rows then m_nMaxRows. Setting m_nMaxRows to 200 however 
> shows that the performance breakdown and the excessive CPU load occurs 
> way before a row has to be removed (starting at approximately 20 rows).
> 
> Well,I just changed my data() function to look as follows:
> 
> QVariant CMultiColumnListModel::data(const QModelIndex& Index, int 
> nRole) const
> {
>    // sanity check
>    if (!Index.isValid()) {
>      return QVariant::Invalid;
>    }
> 
>    if (nRole==Qt::DisplayRole) {
>      // return text data
>      return QString("Test");
>    }
> 
>    // we do not support other roles for now
>    return QVariant::Invalid;
> }
> 
> I know it is stupid but I can't think of a faster data() function. As I 
> expected the problem is exactly the same: very slow with 100 rows and a 
> CPU load of more then 50%.

Then you'll have to hit your app with a profiler, I don't see another way
of finding out where all those cpu-cycles are burnt (certainly not in that
data function).

Andreas

-- 
Perfect day for scrubbing the floor and other exciting things.



More information about the Qt-interest-old mailing list