Maya DAG nodes in QT tools (don’t use string paths)
String paths to Maya objects are _fragile_. This data is stale as soon as you receive it, long paths are better than short, and taking into account namespaces is even better –BUT when it comes down to it, the data is just old as soon as you get it, and there is a better way.
A Full Path that is Never Stale
If you store a node in a Maya Python API MDagPath object, you can ask at any time and get its full path. Because it’s basically a pointer to the object in memory. Here’s an example:
import maya.OpenMaya as om #create and populate an MSelectionList sel = om.MSelectionList() sel.add(cmds.ls(sl=1)[0]) #create and fill an MDagPath mdag = om.MDagPath() sel.getDagPath(0, mdag) #At any time request the current fullpath to the node print mdag.fullPathName() |
CHALLENGE: Can you write a renaming tool that doesn’t use string path node representation? That works with all DG nodes? Without using PyMel? 😉
Embedding Maya Python Objects in PyQT (UserRole)
So.. if we can store a pointer to an object, how do we track that with QT UIs, pass it around, etc? It can be really difficult to find a way to be responsible here, you have all these lists and node representations, and in the past I would try to sync lists of python MDagPath objects, or make a dictionary that mirrors the listView… but there is a way to store arbitrary python objects on list and tree widgetitems!
In this code snipet, I traverse a selection and add all selected nodes to a list, I add ‘UserRole’ data to each and set that data to be an MDagPath:
listWids = [] for item in nodes: sel = om.MSelectionList() sel.add(item) mdag = om.MDagPath() sel.getDagPath(0, mdag) name = mdag.fullPathName() if not self.longNamesCHK.isChecked(): name = name.split('|')[-1] wid = QtGui.QListWidgetItem(listWid) wid.setText(name) wid.setData(QtCore.Qt.UserRole, mdag) listWids.append(wid) |
Now, later when we want to get the full path name of this widgetItem, we just ask it for this data. That returns the MDagPath object, and we can ask the object for the current full path to the node:
print self.drivenNodeLST.currentItem().data(QtCore.Qt.UserRole).fullPathName() |
So this is a good way to have arbitrary data that travels wit the QT node description, which is usually some kind of widget.
keep in mind that this only works for Dag Nodes – not for DgNodes. E.g. this will work with transforms, shapes, but not with, for example, blendShape or skinCluster.
The universal “pointer” to any node is MObject, or, if you need a “let me know when node is deleted” pointer, MObjectHandle. If you later need to know node name, or path, construct MFnDagNode or MFnDgNode and extract info from there.
Comment by Viktoras Makauskas — 2014/09/24 @ 9:42 PM
DG Nodes: Yeah, I put that under ‘CHALLENGE’ (was what I meant by ‘all DG nodes’), I wanted people to figure that out themselves. It’s always the next step.
Comment by admin — 2014/09/25 @ 11:46 AM
[…] message attribute wasn’t this universally cherished thing. In a previous post entitled ‘Don’t use string paths‘, I outlined why storing string paths is the devil’s work, but in that post I talked […]
Pingback by Stumbling Toward 'Awesomeness'The Mighty Message Attribute - Stumbling Toward 'Awesomeness' — 2017/11/13 @ 6:13 PM
[…] of you contacted me regarding my earlier post (Don’t Use String Paths), where I said you should never use string names to keep track of anything even vaguely important […]
Pingback by Stumbling Toward 'Awesomeness'Why Storing String Refs is Dangerous and Irresponsible - Stumbling Toward 'Awesomeness' — 2018/02/19 @ 4:48 PM