[Maya] Custom Outliner Widget

Hello!
I’ve been writing quite a few tools in Maya lately, and I’ve come across this same problem multiple times, but I don’t know how to solve it.

Basically, there are many times when I want to hang onto references to some transform nodes, and keep a list widget of all their up-to-date names. If you change the name or parent of the node in Maya itself, this list widget instantly updates to show the new name. It would let you keep a sub-selection on hand at all times, neat!

I have gotten close by using OpenMaya to get a reference to the actual nodes that would appear in the list.However, my listwidget is not updated by Maya when the node’s name changes. I still have to query all the nodes in the widget about once a second to get their names, and then update the list if they changed. This is obviously not ideal, and it creates all sorts of crashes when dealing with opening other scenes, pressing undo/redo, etc.

To me, it would seem that my only option is to write a custom openmaya node that I would then connect with Plugs to the name attribute of the transform nodes. And then in the compute method of my custom node, I would send a signal to the listWidget with the new name.

But this will dirty up the node graph, and it will leave all these nodes behind when you close the tool. What happens if you open it again, or if two tools each create a copy of that node? It sounds like it would turn into a horrible mess and have bad perf impact.

Does anyone know how to create this behavior without creating a ton of nodes?

Thanks for any thoughts you have!

yopu probably want to use a callback to trigger when a name is changed:
https://help.autodesk.com/view/MAYAUL/2022/ENU/?guid=Maya_SDK_py_ref_class_open_maya_1_1_m_node_message_html
specifically: addNameChangedCallback

I’m not sure if this may be relevant:
cmds.selectionConnection()

In pre-Qt Maya, this was an invisible UI element that live-updates from the scene and synchronizes UI panels together (think: selecting a node in the graph editor outliner and the curves showing up in the attached curve editor)

myOutlinerEditor = cmds.outlinerEditor(showDagOnly=0)
main_conn = cmds.selectionConnection()
sel_conn = cmds.selectionConnection()
cmds.outlinerEditor(myOutlinerEditor , e=1, forceMainConnection=main_conn, selectionConnection=sel_conn)

It still works for those controls. You can add specific nodes (and attributes even) to the selectionConnection and plug it into a custom outlinerEditor, then use

ptr = omui.MQtUtil.findControl('myOutlinerEditor')
myQtOutliner = QtCompat.wrapInstance(long(ptr), QtWidgets.QWidget)

to wrap the outliner and fit it into your tool. I can’t guarantee Maya stability with this approach.

Thanks for showing this to me! So far its working quite well.

I created a subclass of QAbstractListModel that contains a list of openMaya.MObjectHandle() as its data. Whenever a node gets added to this model, I setup one of those MNodeMessage nameChanged callbacks to emit the model’s dataChanged signal on that item for DisplayRole. This instantly updates the ListView widget associated with the model.

Just need to test this for crashy edge cases, but I feel optimistic that this will be the solution.

I did not know about this one, either. If using MNodeMessage doesnt work, I’ll consider using this one. Either way, thanks for sharing!

Have you tried using qt Events? install an event on your Qt ui, and create an event for Maya Qt Ui, when you rename something in maya, you could trigger your Ui to update the names on your list and vice versa, when you are on your Qt ui , you can rename maya’s objects.