问题
I'm really quite new to scripting in Maya. I've been working on a relatively simple tool that creates a simple UI that a user can use to constrain one object to another, but still have the freedom to move that object once its constrained. This is done using nested locators.
If I run the following code I get the error msg:
"# Error: attachObject() takes exactly 1 argument (2 given) # "
import maya.cmds as mc
from functools import partial
#Class to hold UI methods
class UI():
def __init__(self):
self.windowName = "Object Attachment Tool"
self.target = None
self.constraintTarget = None
self.constraintTargetName = ""
def buildUI(self):
#Add code to check if Window already exists
#Window is not re-sizeable
objAttachTool = mc.window( self.windowName, title = "Object Attachment Tool", sizeable = False, widthHeight = ( 1024, 750 ) )
mc.columnLayout( width = 1024 )
mc.text( "\nTarget:\n" )
self.targetTextFieldButtonGrp = mc.textFieldButtonGrp( buttonLabel = "Update", buttonCommand = partial( self.updateTarget ) )
mc.text( "\nObject or Control to be Constrained:\n" )
self.constraintTargetTextFieldButtonGrp = mc.textFieldButtonGrp( buttonLabel = "Update", buttonCommand = partial( self.updateConstraintTarget ) )
test = mc.button( label = "Attach Object", command = self.attachObject )
mc.showWindow()
#This method sets the currently selected object as the target object.
#It also updates the Target textFieldButtonGrp to display the name of the current target object.
def updateTarget(self):
#Get name of selected object
#Assign selected object to a variable to keep track of it
selectedObj = mc.ls( selection = True )
#Check that only one object is selected
if len( selectedObj ) != 1:
print "Select exactly ONE object or control!"
else:
#Update text field with name of selected object
mc.textFieldButtonGrp( self.targetTextFieldButtonGrp, edit = True, text = selectedObj[0] )
#Set selected object as target
self.target = selectedObj
#This method sets the currently selected object as the object to be constrained.
#It also updates the object's textFieldButtonGrp to display the name of the current constraint target
def updateConstraintTarget(self):
#Get the name of the currently selected object
selectedObj = mc.ls( selection = True )
#Make sure exactly ONE object is selected
if len ( selectedObj ) != 1:
print "Select exactly ONE object or control!"
else:
self.constraintTargetName = selectedObj[0]
#Update text field with name of constraint target
mc.textFieldButtonGrp( self.constraintTargetTextFieldButtonGrp, edit = True, text = self.constraintTargetName )
#Update constraintTarget
self.constraintTarget = selectedObj
#This method attaches the constraint target to the target using locators.
def attachObject(self):
#Check that a target and constraint target have been specified
if ( self.target == None ) | ( self.constraintTarget == None ):
print "Make sure you have selected a *Target* and an *Object or Control to be Constrained*"
print "self.target = " + self.target + "\n"
print "self.constraintTarget = " + self.constraintTarget + "\n"
else:
#Create locator named after constraint target
targetLoc = mc.spaceLocator( name = self.constraintTargetName )
#Create locator named constraintTargetName + _MANIP
targetManipLoc = mc.spaceLocator( name = ( self.constraintTargetName + "_MANIP" ) )
#Parent MANIP to constraint target locator
mc.parent ( targetManipLoc, targetLoc )
#Parent Constrain constraint target to _MANIP locator with maintain offset OFF
mc.parentConstraint( targetManipLoc, self.constraintTarget, maintainOffset = False )
#Parent Constrain parent locator to target
mc.parentConstraint( self.target, targetLoc, maintainOffset = False )
UI()
#Create an instance of the UI
userInterface = UI()
userInterface.buildUI()
But if I simply add another argument to the def attachObject method like below...the code works as expected.
#This method attaches the constraint target to the target using locators.
def attachObject(self, huh):
#Check that a target and constraint target have been specified
if ( self.target == None ) | ( self.constraintTarget == None ):
print "Make sure you have selected a *Target* and an *Object or Control to be Constrained*"
print "self.target = " + self.target + "\n"
print "self.constraintTarget = " + self.constraintTarget + "\n"
else:
#Create locator named after constraint target
targetLoc = mc.spaceLocator( name = self.constraintTargetName )
#Create locator named constraintTargetName + _MANIP
targetManipLoc = mc.spaceLocator( name = ( self.constraintTargetName + "_MANIP" ) )
#Parent MANIP to constraint target locator
mc.parent ( targetManipLoc, targetLoc )
#Parent Constrain constraint target to _MANIP locator with maintain offset OFF
mc.parentConstraint( targetManipLoc, self.constraintTarget, maintainOffset = False )
#Parent Constrain parent locator to target
mc.parentConstraint( self.target, targetLoc, maintainOffset = False )
回答1:
Your def attachObject
is written to take no args. In this case, 'self' is automatically passed in as part of the class call so that's the first argument . When you hook it to the button callback it gets an automatic argument passed in as well - thats argument number two. You can verify by printing your 'huh' variable, it will always come out as False
.
A lot of people use the convention of naming values that should be ignored with a single underscore (_) thus: def attachObject(self, _): #....
#or if you might get multiple ignore arguments:
def attachObject(self, *_):
#....
others use ignore or *ignore:
def attachObject(self, *ignore):
#....
TLDR: this is expected behavior
回答2:
The button is given your function attachObject
as a callback, which it will call when the button is pressed. Maya will pass in various arguments that it thinks might be useful, and there is no way to tell it which ones you want. So you just have to be prepared for anything it might throw at you. In this case it appears that buttons call their command
callbacks with one argument. To make your function cope no matter how many arguments it is given, use Python's variable argument list syntax:
def attachObject(*args, **kw):
Now args
is a tuple containing all the positional arguments that are passed, and kw
is a dictionary with all the keyword arguments.
来源:https://stackoverflow.com/questions/21589764/maya-python-takes-exactly-1-argument-2-given