multiple scriptJobs breaks script


#1

When I just use one of the following functions (update_obj_label OR update_shader_label ) and the other function is commented out, the script works more or less fine. I sometimes get the error: “‘sl’ must be passed a boolean argument” and sometimes it breaks after a while, e.g. when switching to an other window (e.g. the webbrowser or so, and then going back to Maya), the txt fields then stop updating.

But what I am the most clueless about is why I can’t run both scriptJobs at the same time!

import maya.cmds as cmds

def curSelTxtShower():
    idManagerUI = cmds.window(title='Vray ID Manager', s = False, wh = (305,500))
    cmds.columnLayout(adj = True)
    cmds.text (l = '__________________________________________ 
 your current selection has this ID: 
')
    curSelObjTxt = cmds.text (l = '', backgroundColor = [0.2, 0.2, 0.2])
    curSelShadTxt = cmds.text (l = '', backgroundColor = [0.2, 0.2, 0.2])
    
    def update_obj_label(*_):
        upCurrentObjectSelShapes = cmds.listRelatives(s=True) or ["nothing selected"]
        upLastobj = upCurrentObjectSelShapes[-1] 
        if upLastobj is not "nothing selected": 
            if cmds.attributeQuery('vrayObjectID', node = upLastobj, ex = True) is True:
                objID = cmds.getAttr(upLastobj + '.vrayObjectID')
                cmds.text(curSelObjTxt, e=True, label = objID)
        else:
            cmds.text(curSelObjTxt, e=True, label = 'curSel has no ObjID assigned')
        
    def update_shader_label(*_):
        upCurrentShaderSel = cmds.ls(sl=True, type= shaderTypes)
        upCurrentShaderSelLast = upCurrentShaderSel[-1]
        if cmds.attributeQuery('vrayMaterialId', node = upCurrentShaderSelLast, ex = True) is True:
            shadID = cmds.getAttr(upCurrentShaderSelLast + '.vrayMaterialId')
            cmds.text(curSelShadTxt, e=True, label = shadID)
            print shadID
        else:
            cmds.text(curSelShadTxt, e=True, label = 'curSel has no MatID assigned')
    
    cmds.scriptJob(event=("SelectionChanged", lambda *x: update_obj_label()), p= curSelObjTxt)
    cmds.scriptJob(event=("SelectionChanged", lambda *x: update_shader_label()), p= curSelShadTxt)
    cmds.showWindow(idManagerUI)     
    
    
curSelTxtShower()
 

#2

In update_shader_label()

upCurrentShaderSel = cmds.ls(sl=True, type= shaderTypes)

shaderTypes is undefined. So this function is actually erroring out every time the scriptjob runs it.


#3

Thank you, I replaced it with materials = True. I now tried to just use one script job that works for shaders and shapes. Therefore I put the checking whether it is a shape or a shader into two different functions and the text label is only updated if one of them is true. Still I sometimes get the error and while the object ids get displayed, the ids on the shaders don’t. Any idea?

import maya.cmds as cmds

def curSelTxtShower():
    idManagerUI = cmds.window(title='Vray ID Manager', s = False, wh = (305,500))
    cmds.columnLayout(adj = True)
    cmds.text (l = '__________________________________________ 
 your current selection has this ID: 
')
    curSelObjTxt = cmds.text (l = '', backgroundColor = [0.2, 0.2, 0.2])

    
# seperate by object and shader selection    
    def upChecker(*_):
        upCurSelection = cmds.ls(sl=True) 
        if len(upCurSelection) > 0:
            upLastobj = cmds.listRelatives(upCurSelection[-1])[-1] or 'nothing selected'
            print upLastobj
            upCurrentShaderSelLast = cmds.ls(upCurSelection[-1], materials=True) or 'nothing selected'
            print upCurrentShaderSelLast
        else: 
            upLastobj = 'nothing selected'
            upCurrentShaderSelLast = 'nothing selected'

#functions that get triggered by script job        
        if upLastobj is not 'nothing selected':
            
            def update_obj_label(*_):
                if cmds.attributeQuery('vrayObjectID', node = upLastobj, ex = True) is True:
                    objID = cmds.getAttr(upLastobj + '.vrayObjectID')
                    cmds.text(curSelObjTxt, e=True, label = objID)
                    print objID
                else:
                    cmds.text(curSelObjTxt, e=True, label = 'curSel has no ObjID assigned')
            update_obj_label()
        
        elif upCurrentShaderSelLast is not 'nothing selected': 
            def update_shader_label(*_):
                if cmds.attributeQuery('vrayMaterialId', node = upCurrentShaderSelLast, ex = True) is True:
                    shadID = cmds.getAttr(upCurrentShaderSelLast + '.vrayMaterialId')
                    cmds.text(curSelObjTxt, e=True, label = shadID)
                    print shadID
                else:
                    cmds.text(curSelObjTxt, e=True, label = 'curSel has no MatID assigned')
                
            update_shader_label()
        
                    
    cmds.scriptJob(event=("SelectionChanged", lambda *x: upChecker()), p=idManagerUI)
    cmds.showWindow(idManagerUI)
    

curSelTxtShower()


#4

The errors you see aren’t the “real” ones, I guess because of the way error messages are dispatched combined with the fact that this is a scriptjob and using maya.cmds. Your problems all seem to be related to dereferencing empty lists.

Example:

upLastobj = cmds.listRelatives(upCurSelection[-1])[-1] or 'nothing selected'

If listRelatives returns an empty list here, which it does when a shader is selected, this code still tries to access its last (nonexistent) element. So the real error is an “index out of range.”

I whipped up a fix below with some finer grained tests, it’s running for me without errors and should give you an idea.

import maya.cmds as cmds

def curSelTxtShower():
    idManagerUI = cmds.window(title='Vray ID Manager', s = False, wh = (305,500))
    cmds.columnLayout(adj = True)
    cmds.text (l = '__________________________________________ 
 your current selection has this ID: 
')
    curSelObjTxt = cmds.text (l = '', backgroundColor = [0.2, 0.2, 0.2])

    
# seperate by object and shader selection    
    def upChecker(*_):
        upCurSelection = cmds.ls(sl=True)
        if upCurSelection:
            shape = cmds.listRelatives(upCurSelection[-1])
            if shape:
                upLastobj = shape[-1]
            else:
                upLastobj = 'nothing selected'
            mat = cmds.ls(upCurSelection[-1], materials=True)
            if mat:
                upCurrentShaderSelLast = mat[-1]
            else:
                upCurrentShaderSelLast = 'nothing selected'
        else: 
            upLastobj = 'nothing selected'
            upCurrentShaderSelLast = 'nothing selected'
        
        print 'upLastobj = ' + upLastobj
        print 'shdr = ' + upCurrentShaderSelLast

#functions that get triggered by script job        
        if upLastobj is not 'nothing selected':
            
            def update_obj_label(*_):
                if cmds.attributeQuery('vrayObjectID', node = upLastobj, ex = True) is True:
                    objID = cmds.getAttr(upLastobj + '.vrayObjectID')
                    cmds.text(curSelObjTxt, e=True, label = objID)
                    print objID
                else:
                    cmds.text(curSelObjTxt, e=True, label = 'curSel has no ObjID assigned')
            update_obj_label()
        
        elif upCurrentShaderSelLast is not 'nothing selected': 
            def update_shader_label(*_):
                if cmds.attributeQuery('vrayMaterialId', node = upCurrentShaderSelLast, ex = True) is True:
                    shadID = cmds.getAttr(upCurrentShaderSelLast + '.vrayMaterialId')
                    cmds.text(curSelObjTxt, e=True, label = shadID)
                    print shadID
                else:
                    cmds.text(curSelObjTxt, e=True, label = 'curSel has no MatID assigned')
                
            update_shader_label()
        
                    
    cmds.scriptJob(event=("SelectionChanged", lambda *x: upChecker()), p=idManagerUI)
    cmds.showWindow(idManagerUI)
    

curSelTxtShower()

P.S. I noticed the labels don’t update if you select nothing, or something that isn’t a mat or doesn’t have a shape (like a set), you might want to add that :slight_smile:

P.P.S. I was sticking to your existing way of determining the type of selection in the code above. A more concise way would be something like this, I don’t know if it meets all your final requirements though:

def upChecker(*_):
        upLastobj = 'nothing selected'
        upCurrentShaderSelLast = 'nothing selected'
        upCurSelection = cmds.ls(sl=True)
        if upCurSelection:
            nodeType = cmds.nodeType(upCurSelection[-1])
            if nodeType == 'transform':
                upLastobj = cmds.listRelatives(upCurSelection[-1])[-1]
            elif cmds.getClassification(nodeType, satisfies='shader'):
                upCurrentShaderSelLast = upCurSelection[-1]
        
        print 'upLastobj = ' + upLastobj
        print 'shdr = ' + upCurrentShaderSelLast
        
        # etc etc

#5

Thank you very very much. Helped me a lot!