Discussion:
[Maya-Python] How to set/ highlight QTreeView selection based on a given string
kiteh
2018-09-13 23:25:40 UTC
Permalink
I have the following QTreeView.
I am trying to set the selection in the QTreeview based on the string I
have derived - eg. '/users/Alice/people' and so the highlighted cell should
only be 'people' that is listed under the Alice level.

tree = {
'users': {
"John" : ["graphics"],
"Alice": ["book", "people"]
}
}

class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.tree_view = QtGui.QTreeView()
self.setCentralWidget(self.tree_view)
self.set_selection()

self.model = QtGui.QStandardItemModel()
self.populateTree(tree, self.model.invisibleRootItem())
self.tree_view.setModel(self.model)
self.tree_view.expandAll()

def populateTree(self, children, parent):
for child in children:
child_item = QtGui.QStandardItem(child)
parent.appendRow(child_item)
if isinstance(children, dict):
self.populateTree(children[child], child_item)

def set_selection(self):
to_set = "/user/Alice/people"
view = self.tree_view.selectionModel()
index = self.model.indexFromItem(to_set)
view.select(QItemSelectionModel.Select|QItemSelectionModel.Rows)


win = MainWindow()
win.show()


Initially I thought that `findItems` may work but unfortunately that is
only for QTreeWidget.
When I tried to do a `set_selection()`, I was prompted with an error that
says "# AttributeError: 'NoneType' object has no attribute 'select' # ", it
seems that the selectionModel is empty..
--
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+***@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/b70070bc-63f6-436a-ad14-1875c13c03f5%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Michael Boon
2018-09-14 04:18:08 UTC
Permalink
You're calling set_selection before you call self.tree_view.setModel. I
would guess that is the problem.
Also I think you've missed "index" from the parameters you're passing to
view.select()
Post by kiteh
I have the following QTreeView.
I am trying to set the selection in the QTreeview based on the string I
have derived - eg. '/users/Alice/people' and so the highlighted cell should
only be 'people' that is listed under the Alice level.
tree = {
'users': {
"John" : ["graphics"],
"Alice": ["book", "people"]
}
}
super(MainWindow, self).__init__(parent)
self.tree_view = QtGui.QTreeView()
self.setCentralWidget(self.tree_view)
self.set_selection()
self.model = QtGui.QStandardItemModel()
self.populateTree(tree, self.model.invisibleRootItem())
self.tree_view.setModel(self.model)
self.tree_view.expandAll()
child_item = QtGui.QStandardItem(child)
parent.appendRow(child_item)
self.populateTree(children[child], child_item)
to_set = "/user/Alice/people"
view = self.tree_view.selectionModel()
index = self.model.indexFromItem(to_set)
view.select(QItemSelectionModel.Select|QItemSelectionModel.Rows)
win = MainWindow()
win.show()
Initially I thought that `findItems` may work but unfortunately that is
only for QTreeWidget.
When I tried to do a `set_selection()`, I was prompted with an error that
says "# AttributeError: 'NoneType' object has no attribute 'select' # ", it
seems that the selectionModel is empty..
--
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+***@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/a6f2eb65-c598-40fb-98c6-c8f764becac5%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
kiteh
2018-09-14 16:30:21 UTC
Permalink
Hey Michael, correct me if I am wrong, I will need to call for my
set_selection case before using the setModel?
--
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+***@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/0fcbfab2-0b5f-463c-83e2-7ba435ae0b8e%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
kiteh
2018-09-14 17:21:55 UTC
Permalink
This is my piece of actual code - https://pastebin.com/pfqDgVtX

As soon as I tried adding the following after Line 292 (after `.setModel`)
for row in range(self.tree_view.rowCount()):
data.append([])
for column in range(self.tree_view.columnCount()):
index = self.tree_view.index(row, column)
data[row].append(str(self.tree_view.data(index).toString()))

I got this error:
# TypeError: rowCount() takes exactly 2 arguments (1 given) #
--
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+***@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/2c10335c-874c-494d-820f-7142980d725a%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Justin Israel
2018-09-14 21:41:29 UTC
Permalink
You have mis-implemented rowCount, columnCount, and hasChildren signatures.
They all take an optional parent index parameter which defaults to an
invalid index meaning no parent. So you need to use index=None or
index=QModelIndex() and handle that case.

Some other notes...

You may want to consider not constructing a handful of QIcon instances on
every call to data(). It gets called alot. You can construct them once for
the whole model and share them. Or at least construct them only when it's a
decoration role.

It is usually not a great idea to conditionally set private fields on
classes such at the _node on your item class. That is the reason you have
to handle exceptions later when accessing the name property. Just always
set it to None or some appropriate default value so that your public
members behave properly. Not having a node should still result in some
empty string name.

It might be a good idea to call the super() method at the end of functions
like data() so that you get default behavior for any unhandled cases.

And also, be careful about modifying the underlying parent/child stuff
without informing the model. I know you begin and end row insertion for the
root. I can't remember if it's ok to add tons of children without also
doing nested begin/end row calls. If you end up seeing the initial state of
your view not showing the plus sign for your root nodes then that could be
why (until it calls hasChildren internally later to discover there are
children)

Justin
Post by kiteh
This is my piece of actual code - https://pastebin.com/pfqDgVtX
As soon as I tried adding the following after Line 292 (after `.setModel`)
data.append([])
index = self.tree_view.index(row, column)
data[row].append(str(self.tree_view.data(index).toString()))
# TypeError: rowCount() takes exactly 2 arguments (1 given) #
--
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
To view this discussion on the web visit
https://groups.google.com/d/msgid/python_inside_maya/2c10335c-874c-494d-820f-7142980d725a%40googlegroups.com
<https://groups.google.com/d/msgid/python_inside_maya/2c10335c-874c-494d-820f-7142980d725a%40googlegroups.com?utm_medium=email&utm_source=footer>
.
For more options, visit https://groups.google.com/d/optout.
--
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+***@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/CAPGFgA0qSrUOavpSYbq5Tn9nRkFqqnQeCFjK55wPBrbMn-U64Q%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.
kiteh
2018-09-14 22:03:00 UTC
Permalink
While I am not very adept in using PyQt yet, and this script that I have
currently have on hand, is taken from a tool (with edited functions here
and there).
I am wondering if you could advise, if it will be better for me to re-write
the whole thing?

Truth be told, as mentioned, that I took the code from somewhere I am not
entirely understanding the script very well.
Even so, if I am do planning to rewrite where need to have some of the
features:

* Populates the tree from a given list of strings - example.
"|ObjectA|ObjectB|ObjectC|..." such that the hierarchy is almost the same
as the ones in the Outliner where you can collapse them
* Appends icon towards each item based on their node type

Will the above features be better/ easily implement using a QTreeWidget,
rather than a QTreeView?
(I mention QTreeWidget as there seems to be more information for some other
features I wanted, eg. for text/ cell color etc)
--
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+***@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/5d51a6af-23da-4c71-9946-bc641dfd0cdb%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Justin Israel
2018-09-15 04:59:10 UTC
Permalink
Post by kiteh
While I am not very adept in using PyQt yet, and this script that I have
currently have on hand, is taken from a tool (with edited functions here
and there).
I am wondering if you could advise, if it will be better for me to
re-write the whole thing?
Truth be told, as mentioned, that I took the code from somewhere I am not
entirely understanding the script very well.
Even so, if I am do planning to rewrite where need to have some of the
* Populates the tree from a given list of strings - example.
"|ObjectA|ObjectB|ObjectC|..." such that the hierarchy is almost the same
as the ones in the Outliner where you can collapse them
* Appends icon towards each item based on their node type
Will the above features be better/ easily implement using a QTreeWidget,
rather than a QTreeView?
(I mention QTreeWidget as there seems to be more information for some
other features I wanted, eg. for text/ cell color etc)
There wasn't anything hugely wrong with the existing code that warrants a
total re-write. I was only pointing out a few adjustments that could be
made.
The thing is though, the current implementation that you shared doesn't
really seem to benefit from having a custom model. It seems like a lot of
work is being done just to replicate a tree structure on your own, and then
provide it to the abstract model to serve to a tree view. Using an abstract
model makes more sense when you already have an existing data structure or
data source that you want to wrap. For instance, you could store basically
nothing and show the dag just by doing api queries as needed, when the
model asks what is at a certain level or under a certain parent. When you
decide to do an abstract model, you have to correctly handle a bunch of
method implementations. It can also be beneficial to use a custom model
when you start hitting performance limitations of the item-based approach.
Honestly you could just be using either a QTreeWidget, or a QTreeView +
QStandardItemModel. Especially if you are starting out with Qt. They
already provide the parent/child items that you are replicating.
QTreeWidget is meant for a really easy interface to just adding items. If
you end up needing more fine-grained control then you can do the view/model
approach. The goal you want to achieve can be done with either one. I
knocked together a quick example of how you can do this with QTreeWidget:

https://pastebin.com/QPwJ3WYH

It can just as easily be switched to view/model instead. I didn't do the
part with the icons, but that is just a matter of calling item.setIcon(0,
theIcon).
Let me know if you have any questions about this code.

Justin
Post by kiteh
--
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
To view this discussion on the web visit
https://groups.google.com/d/msgid/python_inside_maya/5d51a6af-23da-4c71-9946-bc641dfd0cdb%40googlegroups.com
<https://groups.google.com/d/msgid/python_inside_maya/5d51a6af-23da-4c71-9946-bc641dfd0cdb%40googlegroups.com?utm_medium=email&utm_source=footer>
.
For more options, visit https://groups.google.com/d/optout.
--
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+***@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/CAPGFgA28szvQ%3DLqjePgAOB%3DZ%3Dt8TUeqFBQjiSFKgU%3DK66V3GJw%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.
Justin Israel
2018-09-15 05:03:29 UTC
Permalink
I forgot to add a couple code comments that I think would be helpful:

# Break a path like "|root|one|two" into parts and reverse:
# ["|root", "|root|one", "|root|one|two"]
parts = [path.rsplit('|', i)[0] for i in xrange(path.count('|'))]
parts.reverse()

# Get the last name component of the path:
# "|root|one" -> "one"
name = part.rsplit('|', 1)[-1]
Post by Justin Israel
Post by kiteh
While I am not very adept in using PyQt yet, and this script that I have
currently have on hand, is taken from a tool (with edited functions here
and there).
I am wondering if you could advise, if it will be better for me to
re-write the whole thing?
Truth be told, as mentioned, that I took the code from somewhere I am not
entirely understanding the script very well.
Even so, if I am do planning to rewrite where need to have some of the
* Populates the tree from a given list of strings - example.
"|ObjectA|ObjectB|ObjectC|..." such that the hierarchy is almost the same
as the ones in the Outliner where you can collapse them
* Appends icon towards each item based on their node type
Will the above features be better/ easily implement using a QTreeWidget,
rather than a QTreeView?
(I mention QTreeWidget as there seems to be more information for some
other features I wanted, eg. for text/ cell color etc)
There wasn't anything hugely wrong with the existing code that warrants a
total re-write. I was only pointing out a few adjustments that could be
made.
The thing is though, the current implementation that you shared doesn't
really seem to benefit from having a custom model. It seems like a lot of
work is being done just to replicate a tree structure on your own, and then
provide it to the abstract model to serve to a tree view. Using an abstract
model makes more sense when you already have an existing data structure or
data source that you want to wrap. For instance, you could store basically
nothing and show the dag just by doing api queries as needed, when the
model asks what is at a certain level or under a certain parent. When you
decide to do an abstract model, you have to correctly handle a bunch of
method implementations. It can also be beneficial to use a custom model
when you start hitting performance limitations of the item-based approach.
Honestly you could just be using either a QTreeWidget, or a QTreeView +
QStandardItemModel. Especially if you are starting out with Qt. They
already provide the parent/child items that you are replicating.
QTreeWidget is meant for a really easy interface to just adding items. If
you end up needing more fine-grained control then you can do the view/model
approach. The goal you want to achieve can be done with either one. I
https://pastebin.com/QPwJ3WYH
It can just as easily be switched to view/model instead. I didn't do the
part with the icons, but that is just a matter of calling item.setIcon(0,
theIcon).
Let me know if you have any questions about this code.
Justin
Post by kiteh
--
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
To view this discussion on the web visit
https://groups.google.com/d/msgid/python_inside_maya/5d51a6af-23da-4c71-9946-bc641dfd0cdb%40googlegroups.com
<https://groups.google.com/d/msgid/python_inside_maya/5d51a6af-23da-4c71-9946-bc641dfd0cdb%40googlegroups.com?utm_medium=email&utm_source=footer>
.
For more options, visit https://groups.google.com/d/optout.
--
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+***@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/CAPGFgA0-rDKyj-SM9Nki13OTT%3DKn4zDErvYLzfXtv7oddMVRjQ%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.
kiteh
2018-09-19 00:25:23 UTC
Permalink
Hi Justin,

Many thanks for getting back to me on this.

I do have some questions (kindly pardon my questions).

1. Why is there a need to use `enumerate`? It seems that the variable - `i`
is not being used anywhere.. If so, wouldn't it be better to use/ write it
as
for part in (parts):
...

2. I am still not quite understanding the usage of `PATH_ROLE` or
`self.PATH_ROLE`? Especially the latter not being declared anywhere before
it has been used?

3. Lastly, about the `itemFromPath()`, what is the argument - `parent`?
--
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+***@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/646bd0ca-9316-4e09-9b21-28e593231578%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Justin Israel
2018-09-19 02:13:01 UTC
Permalink
Post by kiteh
Hi Justin,
Many thanks for getting back to me on this.
I do have some questions (kindly pardon my questions).
1. Why is there a need to use `enumerate`? It seems that the variable -
`i` is not being used anywhere.. If so, wouldn't it be better to use/ write
it as
...
You can remove that and just use "for part in parts". I forgot to revert
than line when I had removed some test code that was using it.

2. I am still not quite understanding the usage of `PATH_ROLE` or
Post by kiteh
`self.PATH_ROLE`? Especially the latter not being declared anywhere before
it has been used?
PATH_ROLE has been declared as a class variable on line 11. Thus it is
accessible as a member on the class or instances of that class. You could
make it a global to the whole module if you wanted. But it is a bit tidier
to scope the constants with the class that is using them.
Post by kiteh
3. Lastly, about the `itemFromPath()`, what is the argument - `parent`?
`parent` is the parent QTreeWidgetItem where you want to start searching.
Otherwise it defaults to starting from the root of the tree, recursively.
Post by kiteh
--
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
To view this discussion on the web visit
https://groups.google.com/d/msgid/python_inside_maya/646bd0ca-9316-4e09-9b21-28e593231578%40googlegroups.com
<https://groups.google.com/d/msgid/python_inside_maya/646bd0ca-9316-4e09-9b21-28e593231578%40googlegroups.com?utm_medium=email&utm_source=footer>
.
For more options, visit https://groups.google.com/d/optout.
--
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+***@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/CAPGFgA3ujXFkS2RjTmk9V-sVAh-d0zGD-T%3DemDmSLh16xEOMWA%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.
Michael Boon
2018-09-17 03:03:56 UTC
Permalink
In the code in your original post, set_selection sets the view's selection
based on indices from the model. As far as I can tell, you will need to
populate the model and connect it to the view before you do that. I would
expect set_selection to be called after all other setup is complete except
perhaps for signal connections.

The code in your pastebin is very different from the code above though, so
maybe this is irrelevant now?
Post by kiteh
Hey Michael, correct me if I am wrong, I will need to call for my
set_selection case before using the setModel?
--
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+***@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/0246f83b-b2d8-4234-a115-5614a00a4a8f%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Loading...