Results 1 to 2 of 2

Thread: Optimizing filterAcceptsRow() to filter a tree

  1. #1
    Join Date
    Jan 2006
    Innsbruck, Austria
    Thanked 7 Times in 6 Posts
    Qt products

    Default Optimizing filterAcceptsRow() to filter a tree

    I have a custom QSortFilterProxyModel that's being used with a custom model and a QTreeView. Through a QLineEdit and the corresponding signal/slot connection, it allows the user to search for something in the tree of the model and also to hide/show comments which are also nodes in the tree. This is the code:

    Qt Code:
    1. ParsedTreeFilterProxyModel::ParsedTreeFilterProxyModel(QObject *parent)
    2. {
    3. m_commentsVisible = true;
    4. }
    7. bool ParsedTreeFilterProxyModel::commentsVisible()
    8. {
    9. return m_commentsVisible;
    10. }
    13. void ParsedTreeFilterProxyModel::setCommentsVisible(bool visible)
    14. {
    15. m_commentsVisible = visible;
    16. filterChanged();
    17. }
    20. bool ParsedTreeFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
    21. {
    22. QString name = sourceModel()->data( sourceModel()->index(sourceRow, 0, sourceParent) ).toString();
    23. QString value = sourceModel()->data( sourceModel()->index(sourceRow, 1, sourceParent) ).toString();
    24. QString type = sourceModel()->data( sourceModel()->index(sourceRow, 0, sourceParent), Qt::UserRole ).toString();
    25. bool isComment = (type == "ConfigNode");
    26. return ( (!isComment || m_commentsVisible) && (name.contains(filterRegExp()) || value.contains(filterRegExp())) );
    27. }
    To copy to clipboard, switch view to plain text mode 

    Nothing special but as you may guess, when I search for something it only displays the nodes from the top level. When a node is inside some subtree, the parent tree nodes aren't displayed (as the documentation states). Now I want to make it work as it should: display a tree node if there's some child somewhere in its subtree that matches the filter.

    The question is: when filterAcceptsRow() is processing one of those parent tree nodes, do I have to search for nodes that match the filter through the whole subtree (which is obviously very inefficient and time-consuming) or is there a better, more efficient, way to do it? I could think of moving through the tree and when a node matches the filter marking all the parent nodes as "visible" or something like that but AFAIK it's not possible with filterAcceptsRow(). Is it?

    P.S.: I'm using Qt 4.2.

  2. #2
    Join Date
    Jan 2006
    Warsaw, Poland
    Thanked 5,013 Times in 4,791 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits

    Default Re: Optimizing filterAcceptsRow() to filter a tree

    I think you have to scan all the children... What you can do is implement a kind of cache - with each item associate the last searched expression and the return value for that expression, then there won't be any big overhead on the search as each item would be actually searched once and then the cached value will be returned. Pseudocode follows...

    Qt Code:
    1. bool itemMatchesExpression(const QModelIndex &ind, const QRegExp &exp){
    2. if(exp==cache(index).expression) return cache(index).value);
    3. cache(index).expression = exp;
    4. bool v = false;
    5. foreach(QModelIndex i, ind.children()){
    6. v = itemMatchesExpression(i, exp);
    7. if(v) break;
    8. }
    9. cache(index).value = v;
    10. return cache(index).value;
    11. }
    13. bool Model::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const{
    14. return itemMatchesExpression(index(0, sourceRow, sourceParent), expression);
    15. }
    To copy to clipboard, switch view to plain text mode 

  3. The following user says thank you to wysota for this useful post:

    vfernandez (4th January 2007)


Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.