Customized display of files/folders in a QTreeView that is using QFileSystemModel.

976 views
Skip to first unread message

HarshadB

unread,
Jun 10, 2019, 4:22:55 AM6/10/19
to Python Programming for Autodesk Maya
Need some help and direction in understanding QSortFilterProxyModel. I am creating a tool in Maya using PySide2 (Qt.py).

GOAL:
I have already built a filebrowser QTreeView with a QFileSystemModel. Folders and files are both displayed.
I have a filter for files with a certain extension on the source model. (Maybe move this filter to proxy model..)

The files are in this format:
name.0001.ext
name.0002.ext
name.0003.ext

What I want to do is, show the versions of a file in a treeView like this:
- name (not an actual folder, virtual row I want to insert)
--name.0001.ext
--name.0002.ext
--name.0003.ext

So the intention is that QTreeView will always display the files with the names w/o versions. The user has to expand the name to see the version files.
Further on I will implement something that imports the latest file when the "name" is operated on.

HELP:
I believe I can subclass QSortFilterProxyModel to do this. Is this right?
Can someone enlighten me on how to go about it?

Another options is to subclass QAbstractItemModel. I have yet to look deep into this.
I would prefer QSortFilterProxyModel (based on what I have read). But suggestions are welcome.

I will attach some code if required. I will have to extract it from my tool code. 
Thank you.

Justin Israel

unread,
Jun 10, 2019, 7:11:48 AM6/10/19
to python_in...@googlegroups.com
QSortFilterProxyModel is likely where you want to start subclassing. The other option is a QAbstractProxyModel, but that will require you to implement more of the methods, whereas the former is already usable. 
I've got use cases similar to what you subscribe, but it is a private code base so unfortunately I have nothing to share. But I can try to offer some high level advise for now and maybe some more detailed information once I get a chance to look over my code again. But basically you have to implement things like rowCount() to create a virtual new parent tier which is your name without the versions. And stuff like hadChildren(), index(), mapToSource(), and mapFromSource(), so that you can tell the view that your virtual names have children and how to map them to the real source index in the source model. 
The nice thing about using proxy models is that your source model remains the same and you can have multiple views to the same source with different proxies in between that transform the data in a non-destructive way. 

- Justin 

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/df3e4b4a-69e1-432e-9fd9-0164463d8d57%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

HarshadB

unread,
Jun 14, 2019, 6:25:02 AM6/14/19
to Python Programming for Autodesk Maya
Hi Justin, Thank you for the insight. It helped to know that theoretically I am going in the right direction.
I tried quite a bit of things these last few days, a bit of a struggle since I am a bit new to the syntax and structure of Qt.

At this point, I am stuck on adding an extra row using the QSortFilterProxyModel.
I have attached the example code I am using to work on: Example

If I can get a successful empty row inserted, that would be a good start.

- Harshad
On Monday, June 10, 2019 at 8:11:48 PM UTC+9, Justin Israel wrote:
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_maya+unsub...@googlegroups.com.

Justin Israel

unread,
Jun 14, 2019, 8:50:38 PM6/14/19
to python_in...@googlegroups.com
If your model is read-only, then it will be a lot less work and you don't need to implement insertRow(). 
I can try to put together a simplified example of my own implementation when I get back to work. It's a grouping proxy model that is meant to take a table model and create a tree model with a virtual parent item for a configured attribute of the items. As an example, one could say "group on 'category'" and then you would go from this:

ford, car
mazda, car
apple, food
banana, food

to this:

car
    ford
    mazda
food
    apple
    banana

I tried a quick search to see if there are existing examples, and maybe these will give you some more info:

Justin


To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/4afb7027-7593-4c92-aecb-60285c47eec4%40googlegroups.com.

HarshadB

unread,
Jun 17, 2019, 12:08:12 AM6/17/19
to Python Programming for Autodesk Maya
Makes sense.
I was mistakenly trying to use insertRow for the virtual row.  I do intend for the sourceModel to be read-only.
Appreciate the links, I am reading through them though it's a bit difficult for me.
 
I also got that one can use the data method to write the filename for the virtual row.
I am trying to add this code to the subclass to create a new index for the virtual row. (Based on reading this Link. )
There is still a problem with the indexes though: "source.parent()" and "proxy.parent()" won't be understood by the either classes. This example was using table model and won't work with a tree model.

    def index(self, row, column, parent=QtCore.QModelIndex()):

       return self.createIndex(row, column, row)


    def mapFromSource(self, source):

       return self.index(source.row(), source.column(), source.parent())


    def mapToSource(self, proxy):

       if not proxy.isValid() and not self.sourceModel():

           return QtCore.QModelIndex()


        return self.sourceModel().index(proxy.row(), proxy.column(), proxy.parent())


It might seem I am trying to eat more than I can chew right now. I will give it some more time but I will have to leave it due to time constraints and pick it up later when I understand Qt more.
If would be great to have a simplified example, if possible of course.

Thank you for all the help.

- H


On Saturday, June 15, 2019 at 9:50:38 AM UTC+9, Justin Israel wrote:
If your model is read-only, then it will be a lot less work and you don't need to implement insertRow(). 
I can try to put together a simplified example of my own implementation when I get back to work. It's a grouping proxy model that is meant to take a table model and create a tree model with a virtual parent item for a configured attribute of the items. As an example, one could say "group on 'category'" and then you would go from this:

ford, car
mazda, car
apple, food
banana, food

to this:

car
    ford
    mazda
food
    apple
    banana

I tried a quick search to see if there are existing examples, and maybe these will give you some more info:

Justin


To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_maya+unsub...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_maya+unsub...@googlegroups.com.

Justin Israel

unread,
Jun 17, 2019, 2:00:06 AM6/17/19
to python_in...@googlegroups.com
On Mon, Jun 17, 2019 at 4:08 PM HarshadB <bari.h...@gmail.com> wrote:
Makes sense.
I was mistakenly trying to use insertRow for the virtual row.  I do intend for the sourceModel to be read-only.
Appreciate the links, I am reading through them though it's a bit difficult for me.
 
I also got that one can use the data method to write the filename for the virtual row.
I am trying to add this code to the subclass to create a new index for the virtual row. (Based on reading this Link. )
There is still a problem with the indexes though: "source.parent()" and "proxy.parent()" won't be understood by the either classes. This example was using table model and won't work with a tree model.

    def index(self, row, column, parent=QtCore.QModelIndex()):

       return self.createIndex(row, column, row)


    def mapFromSource(self, source):

       return self.index(source.row(), source.column(), source.parent())


    def mapToSource(self, proxy):

       if not proxy.isValid() and not self.sourceModel():

           return QtCore.QModelIndex()


        return self.sourceModel().index(proxy.row(), proxy.column(), proxy.parent())


It might seem I am trying to eat more than I can chew right now. I will give it some more time but I will have to leave it due to time constraints and pick it up later when I understand Qt more.
If would be great to have a simplified example, if possible of course.

Thank you for all the help.

I took a look at my own grouping proxy model implementation and it's alot more work because of its specialization. So I tried to do the most minimal standalone example that I could to illustrate the basics:
https://gist.github.com/justinfx/40e84542d3b768414d3ccbcf03b5e76d

This example is not a "grouping" proxy model like my own implementation. It replicates the virtual row you were asking about.
Regarding that issue of not knowing the proxy vs source parent, you will see how I am handling that. You still have to map between them but being careful not to recurse infinitely. 
Some of the key points in my example are that you have to make use of the createIndex(row, col, internalPointer) in order to attach some kind of indicator data onto your index, which I am using to check if its a virtual index. Now this can cause issues with subclassing from QSortFilterProxyModel because it uses its own values for internal ids and you can segfault the app if you give it something other than an int within range of a pointer address. So on one hand you dont have to implement as many methods when you subclass from QSortFilterProxyModel, but on the other hand it could fight against its implementation. If you were to subclass from QAbstractProxyModel, then you would also need to implement:  columnCount, mapFromSource, and more of the data, index, and parent implementation.

Hope this helps. Its really quite involved to do custom models in Qt.
 
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/e53040af-2502-47dc-8194-fc2bc10b3776%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages