Results 1 to 8 of 8

Thread: Help with Concept: Sorting/filtering TreeView & QAbstractItemModel and filtering

  1. #1
    Join Date
    May 2015
    Posts
    5
    Thanks
    1

    Default Help with Concept: Sorting/filtering TreeView & QAbstractItemModel and filtering

    Can someone help me present a list filtered by the column 1 of the TreeView and the Hierarchical AbstractItemModel?

    I am trying to present a list in the lowerleft of only items that are of Type VARIABLE or STRING BUILDER. I have attempted to use sortFilterProxyModel and am missing something. I guess it only works on items that match when their parent is rootnode.

    I have been beating my head against the wall on how to do this without making two seperate AbstractItem models and attempting to maintain the QmodelIndexes.

    myGui.jpg

  2. #2
    Join Date
    Mar 2011
    Location
    Hyderabad, India
    Posts
    1,882
    Thanks
    3
    Thanked 452 Times in 435 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows
    Wiki edits
    15

    Default Re: Help with Concept: Sorting/filtering TreeView & QAbstractItemModel and filtering

    Quote Originally Posted by bpkelly View Post
    I guess it only works on items that match when their parent is rootnode
    No, the filter is applied recursively to all children. Please re-check the filter expression.
    When you know how to do it then you may do it wrong.
    When you don't know how to do it then it is not that you may do it wrong but you may not do it right.

  3. #3
    Join Date
    May 2015
    Posts
    5
    Thanks
    1

    Default Re: Help with Concept: Sorting/filtering TreeView & QAbstractItemModel and filtering

    Santosh,
    Thanks for your answer. But I think I am still stuck here, per the class reference 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.
    For instance if I change my RegExp to 'CAMERA' and Add a bunch of TYPE: CAMERA it works just fine. I get only a list of cameras in the lower left, when the RegExp filter is applied.

    I think I understand why collapsing a Tree to a Table is not trivial, if you want to maintain all the modelIndexes in the model and the local modelIndexes in the proxymodel, especially if you want to be able to remove or add items in both views. I think that is why the Filter is so constrained. In my case the second non-tree view, I only intend the items to be read only, but select-able. When the item is selected I want to move the reference to a List owned the Variable Aggregate tool (TYPE: STRING BUILDER).

    When the tree is properly populated, my main program will iterate over the tree and create a bunch of TIFF images.

    I am not proficient in C++(so for me, looking at the source code is like a 50yd dash in a 40yd gym), and I am only a rank amateur in python. I do this type of stuff only when needed to eliminate a lot of repetitive stuff for work, not for a living. so forgive me if I am way off base. I feel like a guy who can build Ikea furniture let loose in a master cabinetmakers workshop.

    There are some things that I personally cannot figure out from the documentation:
    1) does removing objects/references from the proxy always remove items from the source?
    2) Is it possible to change all the parents to rootNode in the proxy yet maintain the hierarchy in the source model?
    3) Since my second and third ListViews are read only(in the sense you cannot edit the objects, you can only move them from one listview to the other), can make all the Variable nodes in my source QPersistantModelIndexes then append them to a QList, then MapFromSource in an AbstractProxyList?

    PS. I should add the total number of items in my tree would probably never exceed 100 and mostly hover around 25-30 items, so the additional processor overhead shouldn't be a concern, which people brought up in other topics relating to PersistantIndexes.


    Added after 7 minutes:


    I have been able to figure out child location in the tree for only Variables, can I some how use this info to map to a proxy?
    Figured out mapping.jpg
    Last edited by bpkelly; 25th April 2017 at 15:38.

  4. #4
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Help with Concept: Sorting/filtering TreeView & QAbstractItemModel and filtering

    As you have discovered, you can't use a simple regexp to filter your tree. If I understand your requirement correctly, you want to build a second view of the model that contains only the parts of the original model that have leaves (bottom-most children) that match a certain phrase like "VARIABLE". It also looks like your tree model only contains two columns in each row.

    If that is correct, then you will need to derive from QSortFilterProxyModel to create your own class and override (re-implement) the protected method QSortFilterProxyModel::filterAcceptsRow(). Your override must do this:

    - if the given "row" of the QModelIndex source_parent is a leaf (i.e. QAbstractItemModel::hasChildren() returns false), and the value in column 2 matches your filter string, then you return true, otherwise you return false.

    - if the given row is not a leaf (hasChildren() returns true), then you need to recursively call filterAcceptsRow() for each child of "row" and do the same test as in the first case. You can't simply return true here, you have to go to the leaves of the node to see if any one of them matches. If any leaf node matches, then you want the parents of that node to be included. If no leave node matches, then you don't want any of the parent nodes displayed (except the root node).

    I'm sorry, but I can't make up code off the top of my head and ensure it will work without writing a test program, and I don't have the time for that now.

    I -think- that filterAcceptsRow() is the only method you'll need to override, since the other methods in the proxy model likely use its return value when computing row counts, etc. (If filterAcceptsRow() returns false, then that item and all of its children are ignored, so if an item has children some of which don't pass the filter, then row count will be reduced, and so forth). Be sure you refer to the source model when calling methods like hasChildren(), etc. on the QModelIndex "source_parent" that is passed to this method, otherwise you could get yourself into an infinitely recursive loop.

    You don't need to mess with persistent model indexes or any of that.
    Last edited by d_stranz; 26th April 2017 at 17:53.
    <=== 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.

  5. #5
    Join Date
    May 2015
    Posts
    5
    Thanks
    1

    Default Re: Help with Concept: Sorting/filtering TreeView & QAbstractItemModel and filtering

    d_stranz,
    Thank you for your answer. I think I can pound that one out, but is it also true that all the parent items of TYPES other than VARIABLE will be shown in that resultant filter schema if at the end its a leaf of type VARIABLE?

    If a tree looks like the one below:

    Root
    -Camera
    -Roll
    --Var0
    --job0
    ---Var1
    ---Var2
    ---StringBuilder0
    --job1
    ---Var3

    What I really need is something that I can make a listview or abstractview that returns the following after filtering:
    Var0
    Var1
    Var2
    StringBuilder0
    Var3

    If it still populated with parents which end with leaves of type VARIABLE, very little filtering would have been achieved.

    The idea is the user can aggregate any number of these Variables or String builders into another String Builder class.
    so the user would select one item from the left and use ">" to push it into the String Builder or use "<" to remove it, where item order is respected and builds the resultant string to fill the contents of a Barcode or Datamatrix, or a text in an image.

    Each of these variables have their own types:
    Static
    RandFromSet
    RandIntOfLength
    IncrementorDecrementor

    They can be set to update when their owner gets traversed, or upon being called if the variable is used twice in the same parent.

    And I have successfully built that aspect of the traversing engine with a static set of pre-built nodes. Now I am trying to open it up so the user can create his own schema.

    But the GUI aspect of what I thought the simple task of filtering this tree to only show the leaves of a specific type has really pushed the bounds of my self-educated problem solving abilities.

    I thought of trying to create a hashmap in my basemodel that collects the VARIABLE's as QPersistantModelIndexes that regenerates itself anytime a name or structural change occurs
    Then create an empty proxyModel and fill it with said QPersistantModelIndexes where I locally change the parent to root, and connecting some datachanged-emits. But I cannot figure out how to force indexes into an empty proxymodel. I cannot figure out what the base container in a model is or what it holds, I am guessing its a list of QmodelIndexes. It's probably not virtual anyway... So this is probably a dead end.

    The flailing around is driving me bonkers. It seems like such an easy task, yet not.

    I wonder if I am just over complicating the hell out of it.

    Am I fundamentally breaking the MVC concept here somehow? How would you all do it? Should I forget about ModelView and just bruteforce it with widgets?

    Thanks ahead of time!
    Last edited by bpkelly; 26th April 2017 at 18:48.

  6. #6
    Join Date
    May 2015
    Posts
    5
    Thanks
    1

    Default Re: Help with Concept: Sorting/filtering TreeView & QAbstractItemModel and filtering

    just to confirm, the iteration method returned the parents.... Ugh.

  7. #7
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Help with Concept: Sorting/filtering TreeView & QAbstractItemModel and filtering

    Maybe I misunderstood what you are trying to achieve. The screenshot in your original post showed a tree in both views, so I assumed you wanted a tree where only the branches that had leaves matching your keyword were shown, so yes, what I suggested would show the parents too.

    If all you want is a list of the leaves, then have a look at KDescendentsProxyModel. There is also a KDE FlatProxyModel which converts a tree model into a table model. You might be able to use two layers of proxy models, first to convert your tree into a table, then to filter only rows from the table that contain your keyword.
    <=== 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.

  8. The following user says thank you to d_stranz for this useful post:

    bpkelly (27th April 2017)

  9. #8
    Join Date
    May 2015
    Posts
    5
    Thanks
    1

    Default Re: Help with Concept: Sorting/filtering TreeView & QAbstractItemModel and filtering

    d_stranz,
    Thanks yes it was probably due to ignorance or poor explanation on my part.

    So I was able to find something very similar done in Python on stackoverflow (link)

    It changes names when I change a node Name in either the listview or the TreeView. Which was what I was gunning for, but is not adding items when I add items to the sourceModel thru myGUI , nothing happens, any hints?

    Qt Code:
    1. from PyQt4 import QtCore, QtGui
    2.  
    3.  
    4. class FlatProxyModel(QtGui.QAbstractProxyModel):
    5. def __init__(self, parent = None):
    6. super(FlatProxyModel, self).__init__(parent)
    7.  
    8. @QtCore.pyqtSlot(QtCore.QModelIndex, QtCore.QModelIndex)
    9. def sourceDataChanged(self, topLeft, bottomRight):
    10. self.dataChanged.emit(self.mapFromSource(topLeft), self.mapFromSource(bottomRight))
    11. def buildMap(self, model, parent = QtCore.QModelIndex(), row = 0):
    12. if row == 0:
    13. self.m_rowMap = {}
    14. self.m_indexMap = {}
    15. rows = model.rowCount(parent)
    16. for r in range(rows):
    17. index = model.index(r, 0, parent)
    18. print('row', row, 'item', model.data(index,0))
    19. self.m_rowMap[index] = row
    20. self.m_indexMap[row] = index
    21. row = row + 1
    22. if model.hasChildren(index):
    23. row = self.buildMap(model, index, row)
    24. return row
    25. def setSourceModel(self, model):
    26. self.model = model
    27. QtGui.QAbstractProxyModel.setSourceModel(self, model)
    28. self.buildMap(model)
    29. model.dataChanged.connect(self.sourceDataChanged)
    30. def mapFromSource(self, index):
    31. if index not in self.m_rowMap: return QtCore.QModelIndex()
    32. return self.createIndex(self.m_rowMap[index], index.column())
    33. def mapToSource(self, index):
    34. if not index.isValid() or index.row() not in self.m_indexMap:
    35. return QtCore.QModelIndex()
    36. return self.m_indexMap[index.row()]
    37. def columnCount(self, parent):
    38. return QtGui.QAbstractProxyModel.sourceModel(self)\
    39. .columnCount(self.mapToSource(parent))
    40. def rowCount(self, parent):
    41. return len(self.m_rowMap) if not parent.isValid() else 0
    42. def index(self, row, column, parent):
    43. if parent.isValid(): return QtCore.QModelIndex()
    44. return self.createIndex(row, column)
    45. def parent(self, index):
    46. return QtCore.QModelIndex()
    To copy to clipboard, switch view to plain text mode 



    Thanks So much for even bothering to read it!

    I finally Figured it out!!!
    Added the following to the FlatProxyModel Class:
    Qt Code:
    1. def update(self):
    2. self.model = self.sourceModel()
    3. self.m_indexMap.clear()
    4. self.m_rowMap.clear()
    5. self.buildMap(self.model)
    To copy to clipboard, switch view to plain text mode 
    to the flatten proxy

    then added a Signal/Slots to controller
    Qt Code:
    1. QtCore.QObject.connect(self._model,QtCore.SIGNAL('dataChanged(QModelIndex,QModelIndex)'),self.flattenedProxyModel.update)
    2. QtCore.QObject.connect(self._model,QtCore.SIGNAL('dataChanged(QModelIndex,QModelIndex)'),self.filteredProxyModel.modelReset)
    To copy to clipboard, switch view to plain text mode 
    Last edited by bpkelly; 27th April 2017 at 16:25.

Similar Threads

  1. [Q] sorting&filtering on sqlite with qte-4.7.2
    By jameslee in forum Qt Programming
    Replies: 0
    Last Post: 12th June 2013, 05:20
  2. Sorting and filtering sql data
    By kode in forum Newbie
    Replies: 2
    Last Post: 12th June 2013, 04:11
  3. Replies: 6
    Last Post: 19th June 2012, 15:07
  4. Key filtering
    By phillip_Qt in forum Qt Programming
    Replies: 2
    Last Post: 24th June 2010, 09:10
  5. filtering a TreeView from buttom to top
    By soul_rebel in forum Qt Programming
    Replies: 11
    Last Post: 23rd April 2008, 07:15

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.