Results 1 to 11 of 11

Thread: QTreeView Filter

  1. #1
    Join Date
    May 2008
    Posts
    12
    Thanked 2 Times in 1 Post
    Qt products
    Qt4
    Platforms
    Windows

    Default QTreeView Filter

    Hi All,

    I want to implement a filter for QTreeView.

    Qt Code:
    1. -Apple
    2. |____ Object_01
    3. |____ Object_02
    4. |____ XYZ
    5. -Banana
    6. |____ Object_03
    7. |____ Lemon
    8. - Orange
    9. |____ Rabbit
    10. |____ Object_04
    11. |____ Object_05
    To copy to clipboard, switch view to plain text mode 

    I have to use a LineEdit for dynamic filter. (Connection to textchange I have done)
    Conditions:
    1> With every Stroke of letter whole tree should be filtered.
    e.g. If in lineEdit I say Obj it should show, important thing is every word in the list should start with Obj.

    Qt Code:
    1. -Apple
    2. |____ Object_01
    3. |____ Object_02
    4. -Banana
    5. |____ Object_03
    6. - Orange
    7. |____ Object_04
    8. |____ Object_05
    To copy to clipboard, switch view to plain text mode 


    I tried using simple filter example(BasisSortFilter) it works perfectly fine for tree with only parents and no children. However it's not working with tree with childrens (above example)
    This quote I read while going through the documentation of qsortfilterproxymodel.
    For hierarchical models, the filter is applied recursively to all children. If a parent item doesn't match the filter, none of its children will be shown.

    This slot is connected to lineEdit with

    Qt Code:
    1. connect(FilterLineEdit, SIGNAL(textChanged(QString)),this, SLOT(filterChanged()));
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. void FilterDialog::filterChanged()
    2. {
    3. QRegExp::PatternSyntax syntax = QRegExp::RegExp;
    4. Qt::CaseSensitivity caseSensitivity = Qt::CaseInsensitive;
    5. QString strPattern = "^" + FilterLineEdit->text();
    6. QRegExp regExp(strPattern, caseSensitivity);
    7. proxyModel->setFilterRegExp(regExp);
    8. }
    To copy to clipboard, switch view to plain text mode 

    Thanks in advance.

  2. #2
    Join Date
    Jan 2006
    Location
    Germany
    Posts
    4,380
    Thanks
    19
    Thanked 1,004 Times in 913 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows Symbian S60
    Wiki edits
    5

    Default Re: QTreeView Filter

    Well it is up to you. Subclass QSortFilterProxyModel and make sure parents get only invalid if no children passes the test.

  3. #3
    Join Date
    May 2008
    Posts
    12
    Thanked 2 Times in 1 Post
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QTreeView Filter

    Hi Lykurg,

    Thanks for your reply, can you provide some code for that ?


    Thanks

  4. #4
    Join Date
    Jan 2006
    Location
    Germany
    Posts
    4,380
    Thanks
    19
    Thanked 1,004 Times in 913 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows Symbian S60
    Wiki edits
    5

    Default Re: QTreeView Filter

    No, but simply subclass and reimplement QSortFilterProxyModel::filterAcceptsRow(). The detailed description is good and there are some examples in the documentation as well. Try it first yourself, and if you can't manage it, post the code you have such far and we work on from that point.

  5. #5
    Join Date
    May 2008
    Posts
    12
    Thanked 2 Times in 1 Post
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: QTreeView Filter

    This problem is solved, I have put code for reference.

    Thanks to everyone, this forum rocks...


    Qt Code:
    1. QAbstractItemModel *FilterDialog::createModel(QObject *parent)
    2. {
    3.  
    4. QStandardItemModel *model = new QStandardItemModel(5, 1, parent);
    5. for( int r=0; r<5; r++ )
    6. {
    7. QStandardItem *item = new QStandardItem( QString("Row:%0").arg(r));
    8.  
    9. for( int i=0; i<3; i++ )
    10. {
    11. QStandardItem *child = new QStandardItem( QString("Item %0").arg(i) );
    12. child->setEditable( false );
    13. item->appendRow( child );
    14. }
    15.  
    16. model->setItem(r, 0, item);
    17. }
    18.  
    19. model->setHorizontalHeaderItem( 0, new QStandardItem( "Column 1" ) );
    20.  
    21. return model;
    22. }
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. FilterDialog::FilterDialog(QWidget *parent)
    2. : QDialog(parent)
    3. {
    4. setupUi(this);
    5. proxyModel = new SongTreeProxyFilter;
    6. proxyModel->setDynamicSortFilter(true);
    7. treeView->setModel(proxyModel);
    8. QAbstractItemModel * itemModel = createModel(this);
    9. proxyModel->setSourceModel(itemModel);
    10.  
    11. connect(FilterLineEdit, SIGNAL(textChanged(QString)),
    12. this, SLOT(filterChanged()));
    13.  
    14. }
    15.  
    16. void FilterDialog::filterChanged()
    17. {
    18. QRegExp::PatternSyntax syntax = QRegExp::RegExp;
    19.  
    20. Qt::CaseSensitivity caseSensitivity = Qt::CaseInsensitive;
    21. QString strPattern = "^" + FilterLineEdit->text();
    22. QRegExp regExp(strPattern, caseSensitivity);
    23.  
    24. proxyModel->setFilterRegExp(regExp);
    25. }
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. //SubClass of QSortFilterProxyModel
    2. bool TreeProxyFilter::filterAcceptsRow(int sourceRow,
    3. const QModelIndex &sourceParent) const
    4. {
    5. QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
    6. return ShowThis(index);
    7. }
    8.  
    9. bool TreeProxyFilter::ShowThis(const QModelIndex index) const
    10. {
    11. bool retVal = false;
    12. //Gives you the info for number of childs with a parent
    13. if ( sourceModel()->rowCount(index) > 0 )
    14. {
    15. for( int nChild = 0; nChild < sourceModel()->rowCount(index); nChild++)
    16. {
    17. QModelIndex childIndex = sourceModel()->index(nChild,0,index);
    18. if ( ! childIndex.isValid() )
    19. break;
    20. retVal = ShowThis(childIndex);
    21. if (retVal)
    22. {
    23. break;
    24. }
    25. }
    26. }
    27. else
    28. {
    29. QModelIndex useIndex = sourceModel()->index(index.row(), 0, index.parent());
    30. QString type = sourceModel()->data(useIndex, Qt::DisplayRole).toString();
    31. if ( ! type.contains(filterRegExp()))
    32. {
    33. retVal = false;
    34. }
    35. else
    36. {
    37. retVal = true;
    38. }
    39. }
    40. return retVal;
    41. }
    To copy to clipboard, switch view to plain text mode 

  6. #6
    Join Date
    Feb 2012
    Posts
    2
    Qt products
    Qt4 Qt/Embedded

    Default Re: QTreeView Filter

    Esta implementación busca si los hijos cumple la condición y no utiliza funciones recursivas

    Qt Code:
    1. bool SortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
    2. {
    3. QList<QModelIndex> children;
    4. children << sourceModel()->index(source_row, 0, source_parent);
    5.  
    6. bool show = false;
    7. for(int i = 0; i < children.length(); i++)
    8. {
    9. if(show) break;
    10.  
    11. // Add sub Nodos
    12. //
    13. for(int c = 0; c < sourceModel()->rowCount(children[i]) ;c++)
    14. children.append(children[i].child(c,0));
    15.  
    16. QString type = sourceModel()->data(children[i], Qt::DisplayRole).toString();
    17. show = type.contains(filterRegExp());
    18. }
    19. return show;
    20. }
    To copy to clipboard, switch view to plain text mode 
    Last edited by Bycross028; 17th December 2014 at 12:56.

  7. #7
    Join Date
    Dec 2013
    Posts
    14
    Thanks
    2
    Thanked 2 Times in 1 Post
    Qt products
    Qt4
    Platforms
    MacOS X Windows

    Default Re: QTreeView Filter

    the "filterAcceptsRow" method seems to be meant for recursion, so the shortest way would be (given colum 0 needs to be checked):

    Qt Code:
    1. bool MySortFilterProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const
    2. {
    3. QModelIndex index = sourceModel()->index(row, 0, parent);
    4.  
    5. if (!index.isValid())
    6. return false;
    7.  
    8. if (index.data().toString().contains(filterRegExp()))
    9. return true;
    10.  
    11. int rows = sourceModel()->rowCount(index);
    12. for (row = 0; row < rows; r++)
    13. if (filterAcceptsRow(row, index))
    14. return true;
    15.  
    16. return false;
    17. }
    To copy to clipboard, switch view to plain text mode 
    Last edited by t_3; 27th January 2015 at 11:34.

  8. The following 2 users say thank you to t_3 for this useful post:

    d_stranz (27th January 2015), Opa114 (25th December 2018)

  9. #8
    Join Date
    Dec 2018
    Posts
    3
    Thanks
    2
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: QTreeView Filter

    How did i get the recursive solution work for not only the first column? I want to filter on the first and second column. How can i do this?
    Or maybe better: How must i modify the official qt example (see here) so that i works with the child items of a row. if i remove here the index2 stuff, the function checks column 0 andcolumn 1, which is what i wanted, but it does not check the children.

    Qt Code:
    1. bool MySortFilterProxyModel::filterAcceptsRow(int sourceRow,
    2. const QModelIndex &sourceParent) const
    3. {
    4. QModelIndex index0 = sourceModel()->index(sourceRow, 0, sourceParent);
    5. QModelIndex index1 = sourceModel()->index(sourceRow, 1, sourceParent);
    6. QModelIndex index2 = sourceModel()->index(sourceRow, 2, sourceParent);
    7.  
    8. return (sourceModel()->data(index0).toString().contains(filterRegExp())
    9. || sourceModel()->data(index1).toString().contains(filterRegExp()))
    10. && dateInRange(sourceModel()->data(index2).toDate());
    11. }
    To copy to clipboard, switch view to plain text mode 
    Last edited by Opa114; 25th December 2018 at 00:58.

  10. #9
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    4,170
    Thanks
    235
    Thanked 662 Times in 652 Posts
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: QTreeView Filter

    If I understand your question correctly, what you are saying is that if you return "false" for a certain row, then the children of that row are ignored, right? Unfortunately, that is how QSortFilterProxyModel works - as soon as one level of a tree returns false for filterAcceptsRow(), that row and all of its children are removed from further consideration.

    Think about what it would mean if it didn't work that way and continued the recursion into children. What kind of tree would that result in? A bunch of children, but no parent for those children because the parent row had been rejected.

    You probably need to rethink how you really want your filtering to work and maybe work out a few test cases by hand so you can get the logic right.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  11. #10
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,420
    Thanks
    37
    Thanked 1,545 Times in 1,495 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: QTreeView Filter

    In such a case it might be easier to implement the filtering in the model itself.

    Using a proxy looks convenient at first but it often has actually higher complexity due to working in such an abstracted way.

    Cheers,
    _

  12. #11
    Join Date
    Dec 2018
    Posts
    3
    Thanks
    2
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: QTreeView Filter

    Thanks for the hints. I got it work for my needs, so my code of filterAcceptsRow() looks this:

    Qt Code:
    1. bool MySortFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
    2. {
    3. QModelIndex index0 = sourceModel()->index(sourceRow, 0, sourceParent);
    4. QModelIndex index1 = sourceModel()->index(sourceRow, 1, sourceParent);
    5.  
    6. if (!index0.isValid())
    7. return false;
    8.  
    9. if (sourceModel()->data(index0).toString().contains(filterRegExp())
    10. || sourceModel()->data(index1).toString().contains(filterRegExp()))
    11. return true;
    12.  
    13. int rows = sourceModel()->rowCount(index0);
    14. for (int row = 0; row < rows; row++) {
    15. if (filterAcceptsRow(row, index0))
    16. return true;
    17. }
    18.  
    19. return false;
    20. }
    To copy to clipboard, switch view to plain text mode 

    So this works for my needs. If it found a children that matches the criteria the parentwill be shown, too, which is okay for my needs.

Similar Threads

  1. QTreeView::problems with the filter
    By Mint87 in forum Qt Programming
    Replies: 4
    Last Post: 18th November 2011, 13:03
  2. QFileDialog filter
    By wirasto in forum Newbie
    Replies: 12
    Last Post: 20th January 2010, 13:40
  3. Convolution filter
    By toutarrive in forum Qt Programming
    Replies: 5
    Last Post: 21st October 2009, 14:55
  4. Filter a table
    By Nefastious in forum Newbie
    Replies: 1
    Last Post: 18th September 2009, 11:45
  5. regarding keyboard filter....
    By sar_van81 in forum Qt Programming
    Replies: 1
    Last Post: 2nd January 2007, 17:28

Bookmarks

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.