更新连接到setAttr

时间:2018-01-25 20:35:45

标签: python maya

我在脚本和法语方面有点新意,所以如果我的解释不是很清楚的话,请不要理我。

我试图在Maya中创建一个脚本来轻松管理动画的键值。

所以我创建了一个窗口,用另一个组织复制Maya的ChannelBox。现在我尝试在不同的textField(transX,transY ..)中自动设置和更新所选对象的属性值。

我发现了一些关于一个名为scriptJob的命令的信息可以帮助我,但是没有找到任何类似我的上下文或关于如何将它放在我的代码中的最新信息。

以下是我现在所拥有的:

transX_value = cmds.textField( w=100 , h=22 , tx= cmds.getAttr("%s.translateX" %selected[0]) )

所以现在我需要一些关于在textField中连接更新函数的帮助,所以当它改变并按Enter时,属性也会改变所以我认为我需要在我的函数中插入一个scriptJob但是我不知道怎么做。

def updateValues () :

for sel in selection :
    sel_attr = cmds.getAttr("%s+.name" %selected[0])
    cmds.setAttr( "%s+.name" , textField)

代码的结尾当然不对。

感谢您的帮助。

4 个答案:

答案 0 :(得分:1)

您的代码中存在一些问题。我试着解释可以改进的地方。

import maya.cmds as cmds

wName = "Key_Manager"
selected = cmds.ls(selection=True)

if cmds.window(wName , exists = 1) : cmds.deleteUI(wName)

window = cmds.window( wName, s=0)
form = cmds.formLayout (wName +'Form')

translateMenu = cmds.text ( l='TranslateX' ,  fn="boldLabelFont")

translateMenu 真的很误导,它是一个简单的标签。如果您在一段时间后返回代码,您可能无法立即知道这意味着什么,因为您也可以在窗口中使用菜单。

cmds.formLayout( form , e=1 , attachForm = [ (translateMenu , 'top' , 45) , (translateMenu, 'left' , 50 ) ] )

transX_value = cmds.textField( w=100 , h=22 , tx= cmds.getAttr("%s.translateX" %selected[0]) , ec = 'updateValue( "Key_Manager|translateX|transX" )' )

对UI元素进行硬编码不是一个好主意。在Maya中,您永远不会知道您的UI元素是否总是以相同的方式命名。您可以通过在两个命令中分隔textField创建来解决此问题:

transX_value = cmds.textField( w=100 , h=22 , tx= cmds.getAttr("%s.translateX" %selected[0]))
cmds.textField(transX_value, edit=True, ec = 'updateValue("%s")'%transX_value)

你可以使用floatField而不是textField,在这种情况下似乎更合适。

cmds.formLayout( form , e=1 , attachForm = [ (transX_value , 'top' , 68) , (transX_value , 'left' , 50 ) ] )

cmds.window( wName,e=1)
cmds.showWindow(window)

def updateValue (name) :    
    name = name.split('|')
    name = name[-1]
    attr = name.split('|')
    attr = name[1]

    cmds.setAttr ("%s + .attr" %selected, name+'_value'.text.getAttr('value'))

由于某些原因, updateValue()永远无法正常工作。您要做的是从文本字段中检索值并将其应用于对象。 让我们想象你使用改进版本和ec - 命令:

def updateValue (name) :    
    value = cmds.textField(name, query=True, text=True)

无需拆分任何内容,只需使用名称即可获取值:

cmds.setAttr ("%s + .attr" %selected, name+'_value'.text.getAttr('value'))

您尝试将值分配给对象,但使用列表(选择是列表)并且没有任何名为" attr"。所以第一部分是:

cmds.setAttr("%s.translateX"%selected[0]....

在第二部分中,您将面向对象的方法与maya特定的文本方法混合使用(如果您想使用对象,请使用pymel)。所以这更合适:

cmds.setAttr("%s.translateX"%selected[0], float(value))

因为你使用textField而不是floatField需要float()。

希望对此有所帮助。

答案 1 :(得分:0)

出错了。

第一步,我需要了解如何在tx更改时更新属性。 在第二步,如果我选择另一个对象,我需要自动更新值。

顺便说一下,我发现了更多关于enterCommand的事情,并尝试这样的事情,这是行不通的。

transX_value = cmds.textField( w=100 , h=22 , tx= cmds.getAttr("%s.translateX" %selected[0]) , ec = 'updateValue( "Key_Manager|translateX|transX" )' )


def updateValue (name) :

    name = name.split('|')
    name = name[-1]
    attr = name.split('|')
    attr = name[1]

    cmds.setAttr ("%s + .attr" %selected, textField.tx)`

答案 2 :(得分:0)

以下是我做过的最后一个简单版本的简单版本:

import maya.cmds as cmds

wName = "Key_Manager"
selected = cmds.ls(selection=True)

# Make a new window
#
if cmds.window(wName , exists = 1) : cmds.deleteUI(wName)

window = cmds.window( wName, s=0)
form = cmds.formLayout (wName +'Form')

# Translate
#
translateMenu = cmds.text ( l='TranslateX' ,  fn="boldLabelFont")
cmds.formLayout( form , e=1 , attachForm = [ (translateMenu , 'top' , 45) , (translateMenu, 'left' , 50 ) ] )

transX_value = cmds.textField( w=100 , h=22 , tx= cmds.getAttr("%s.translateX" %selected[0]) , ec = 'updateValue( "Key_Manager|translateX|transX" )' )
cmds.formLayout( form , e=1 , attachForm = [ (transX_value , 'top' , 68) , (transX_value , 'left' , 50 ) ] )


# Show Window
cmds.window( wName,e=1)
cmds.showWindow(window)


# Update Value
#
def updateValue (name) :

    name = name.split('|')
    name = name[-1]
    attr = name.split('|')
    attr = name[1]

    cmds.setAttr ("%s + .attr" %selected, name+'_value'.text.getAttr('value'))

您需要选择一个对象才能启动它。 谢谢你的帮助。

答案 3 :(得分:0)

好的,我试着给你举个很多评论的例子。询问有关它的任何问题。我已将脚本作业放入'''''''。你必须找出适合你的方法。

import maya.cmds as cmds
from functools import partial

# Update Value
# I've changed the function and add the var attr to be more procedural
# and i've added *args, because command flags in maya add a default last argument True that
# is not useful
def updateValue (name, attr, *args) :    
    value = cmds.textField(name, query=True, text=True)
    #I've added the attr to be more procedural
    cmds.setAttr("%s.%s" %(selected[0], attr), float(value))

wName = "Key_Manager"
# Not enough protected varaible selected : should be inside a dic or a variable name more complicated
# as : Key_Manager_sel = cmds.ls(selection=True)
# see forward in the end on the update method
selected = cmds.ls(selection=True)

# Make a new window
#
if cmds.window(wName , exists = 1) : cmds.deleteUI(wName)

window = cmds.window( wName, s=0)
form = cmds.formLayout (wName +'Form')

# your attr should be not harcoded, see line 29, in order to be procedural
attr = 'translateX'
# Translate
# Create only one element one layout to place in your formLayout
wdgSetField = cmds.rowLayout(numberOfColumns=2)
# for ui nomenclature, i use lb_ for label or text (in Qt, it is cmds.text is a QLabel)
# attr[0].upper() is your 'T' and attr[1:] is : 'ranslateX' 
lb_Tx = cmds.text ( l=attr[0].upper() + attr[1:] ,  fn="boldLabelFont", p=wdgSetField)
# same here i would use a prefix because it is not really your value tx
# as haggi krey told you, you have to attach the function in a second part in order to have the name of the textField
transX_value = cmds.textField( w=100 , h=22 , tx= cmds.getAttr("%s.%s" %(selected[0], attr)), p=wdgSetField)
cmds.textField(transX_value, edit=True, ec = partial(updateValue, transX_value, attr))

# Just attach it to the form layout
cmds.formLayout( form , e=1 , attachForm = [ (wdgSetField , 'top' , 45) , (wdgSetField, 'left' , 50 ) ] )
# from line 17 to 28, should be a def because you will repeat this code for many attributes :
'''
def widget_attr(attr, pos=list):
    """
    parameter:: attr:: <str> long name of an attr, ie : 'translateX'
    parameter:: pos:: <list> [45, 50] take exactly two integer
    """
    wdgSetField = cmds.rowLayout(numberOfColumns=2, p=form)
    lb_attr = cmds.text ( l=attr[0].upper() + attr[1:] ,  fn="boldLabelFont", p=wdgSetField)
    le_value = cmds.textField( w=100 , h=22 , tx= cmds.getAttr("%s.%s" %(selected[0], attr)), p=wdgSetField)
    cmds.textField(le_value, edit=True, ec = partial(setValue, le_value, attr))
    cmds.formLayout( form , e=1 , attachForm = [ (wdgSetField , 'top' , pos[0]) , (wdgSetField, 'left' , pos[1] ) ] )
    # return the line edit for futur use, it is just here for knowledge (your can return a list of items too)
    return [attr, le_value]

# Why using dictionnary ? it could be a list but if you want to update every value on selection change,
# you will have to store this textField somewhere
ui_dic = {}
ui_dic['tx_prm'] = widget_attr('translateX', [45, 50])
ui_dic['ty_prm'] = widget_attr('translateY', [90, 100])
ui_dic['rx_prm'] = widget_attr('rotateX', [140, 50])

def updateTextField(selected):
    # Loop through the textField
    for k in ui_dic.keys():
        # in theory, i could just take 'tx_prm' and strip _prm  to find the attr but :
        attr =  ui_dic[k][0]
        le_Name = ui_dic[k][1]
        value = cmds.getAttr("%s.%s" %(selected[0], attr))
        cmds.textField(le_Name, e=True, text=str(value))

def setValue(name, attr, *args):
    value = cmds.textField(name, query=True, text=True)
    cmds.setAttr("%s.%s" %(selected[0], attr), float(value))

# For the script Job Part :

def onChangeSel():
    selected = cmds.ls(selection=True)
    updateTextField(selected)

# On selection change, update selection and textField
scriptJobID = cmds.scriptJob(e=["SelectionChanged", onChangeSel], protected=True)
# Script Job need to be deleted when the ui is closed or they will stack :
scriptJobWinClose()

def scriptJobWinClose():
    # create another scriptJob that will run once when the ui will be closed and run the function :
    cmds.scriptJob(runOnce=True, uid=[wName, closeEvent])

def closeEvent():
    # We just kill the scriptJob here but you could do really anything you want on the window closing  
    cmds.scriptJob(kill=scriptJobID, force=True)
'''


# Show Window
cmds.window( wName,e=1)
cmds.showWindow(window)

---编辑---

import maya.cmds as cmds
from functools import partial

def updateTextField(selected):
    # Loop through the textField
    for k in ui_dic.keys():
        # in theory, i could just take 'tx_prm' and strip _prm  to find the attr but :
        attr =  ui_dic[k][0]
        le_Name = ui_dic[k][1]
        value = cmds.getAttr("%s.%s" %(selected[0], attr))
        cmds.textField(le_Name, e=True, text=str(value))

def setValue(name, attr, *args):
    value = cmds.textField(name, query=True, text=True)
    cmds.setAttr("%s.%s" %(selected[0], attr), float(value))

wName = "Key_Manager"
# Not enough protected varaible selected : should be inside a dic or a variable name more complicated
# as : Key_Manager_sel = cmds.ls(selection=True)
# see forward in the end on the update method
selected = cmds.ls(selection=True)

# Make a new window
#
if cmds.window(wName , exists = 1) : cmds.deleteUI(wName)

window = cmds.window( wName, s=0)
form = cmds.formLayout (wName +'Form')

def widget_attr(attr, pos=list):
    """
    parameter:: attr:: <str> long name of an attr, ie : 'translateX'
    parameter:: pos:: <list> [45, 50] take exactly two integer
    """
    wdgSetField = cmds.rowLayout(numberOfColumns=2, p=form)
    lb_attr = cmds.text ( l=attr[0].upper() + attr[1:] ,  fn="boldLabelFont", p=wdgSetField)
    le_value = cmds.textField( w=100 , h=22 , tx= 0, p=wdgSetField)
    cmds.textField(le_value, edit=True, ec = partial(setValue, le_value, attr))
    cmds.formLayout( form , e=1 , attachForm = [ (wdgSetField , 'top' , pos[0]) , (wdgSetField, 'left' , pos[1] ) ] )
    # return the line edit for futur use, it is just here for knowledge (your can return a list of items too)
    return [attr, le_value]

# Why using dictionnary ? it could be a list but if you want to update every value on selection change,
# you will have to store this textField somewhere
ui_dic = {}
ui_dic['tx_prm'] = widget_attr('translateX', [45, 50])
ui_dic['ty_prm'] = widget_attr('translateY', [90, 100])
ui_dic['tz_prm'] = widget_attr('translateZ', [150, 100])
ui_dic['rx_prm'] = widget_attr('rotateX', [200, 50])
# You can add any other textfied parameter like scaleX...etc


'''
# For the script Job Part :

def onChangeSel():
    selected = cmds.ls(selection=True)
    updateTextField(selected)

# On selection change, update selection and textField
scriptJobID = cmds.scriptJob(e=["SelectionChanged", onChangeSel], protected=True)
# Script Job need to be deleted when the ui is closed or they will stack :
scriptJobWinClose()

def scriptJobWinClose():
    # create another scriptJob that will run once when the ui will be closed and run the function :
    cmds.scriptJob(runOnce=True, uid=[wName, closeEvent])

def closeEvent():
    # We just kill the scriptJob here but you could do really anything you want on the window closing  
    cmds.scriptJob(kill=scriptJobID, force=True)
'''


# Show Window
cmds.window( wName,e=1)
cmds.showWindow(window)
updateTextField(selected)