Maya Python: cmds.button( ) with UI passing variables and calling a function?

丶灬走出姿态 提交于 2019-12-18 11:19:34

问题


First of all, this seems to be a great place to learn more about programming. I've written a maya python script, where both functions work, I'm having trouble getting the UI button to call the superExtrude() function, though. The first function does the geometric mesh manipulations and the second one should produce the UI for the user inputs:

import maya.cmds as cmds

def superExtrude(extrScale, extrDist):
    """Loops through a list of selected meshes and extrudes all of the mesh faces to produce a polygon frame, based on existing mesh tesselations"""
    myObjectLt = cmds.ls(selection=True)

    for i in range(len(myObjectLt)):
        numFaces = cmds.polyEvaluate(face=True)
        item = myObjectLt[i] + ".f[:]"
        cmds.select(clear=True)
        cmds.select(item, replace=True)

        #extrude by scale
        cmds.polyExtrudeFacet(constructionHistory=True, keepFacesTogether=False, localScaleX=extrScale, localScaleY=extrScale, localScaleZ=extrScale)
        selFaces = cmds.ls(selection=True)
        cmds.delete(selFaces)

        #extrude by height
        cmds.select(item, replace=True)
        cmds.polyExtrudeFacet(constructionHistory=True, keepFacesTogether=True, localTranslateZ=extrDist)

def extrWindow():
    """Creates the user interface UI for the user input of the extrusion scale and height"""
    windowID = "superExtrWindow"

    if cmds.window(windowID, exists=True):
        cmds.deleteUI(windowID)

    cmds.window(windowID, title="SuperExtrude", sizeable=False, resizeToFitChildren=True)
    cmds.rowColumnLayout(numberOfColumns=2, columnWidth=[(1,120),(2,120)], columnOffset=[1,"right",3])

    cmds.text(label="Extrusion Scale:")
    extrScaleVal = cmds.floatField(text=0.9)
    cmds.text(label="Extrusion Height:")
    extrDistVal = cmds.floatField(text=-0.3)
    cmds.separator(height=10, style="none")
    cmds.separator(height=10, style="none")
    cmds.separator(height=10, style="none")

    cmds.button(label="Apply", command=superExtrude(extrScaleVal, extrDistVal))
    cmds.showWindow()

extrWindow()

I'm pretty new to python and maya scripting, so any help would be greatly appreciated. :)


回答1:


Im not sure if this is the answer you want but what you have to know about maya "commands" flags :

  • If you want to put a function in a button call, you need to pass in the function name without any arguments (eg : command = myFunction) (get rid of the ending brackets "()" )

  • in your function, you need to add a "*args" because the maya button always passes an argument (I think it's "False") (eg : def myFunction(customArg1, customArg2, *args) )

  • If you want to pass arguments in the button signal, you need to use the partial function from the functools module (from functools import partial) and use it like this: cmds.button( command = partial(myFunction, arg1, arg2, kwarg1=value1, kwarg2=value2) )

One more thing, about pymel and cmds... it's probably a never ending story but pymel is not almighty... When you have to deal with a lot of informations (like getting a vertices list on a mesh), pymel can be something like 40x slower than a simple maya commands. It has its pros and its cons... If you've just started with python, I wouldn't recommend to get into pymel right now. Get familiar with the syntax and the commands, and when you're ok, switch to pymel (which is very useful when you are dealing with objects creation)

Hope this helped, Cheers

Edit :

Based on your first post, what you need to change in your code to make it work is :

import maya.cmds as cmds
from functools import partial

#You need to add the *args at the end of your function
def superExtrude(extrScaleField, extrDistField, *args):
    """Loops through a list of selected meshes and extrudes all of the mesh faces to produce a polygon frame, based on existing mesh tesselations"""
    myObjectLt = cmds.ls(selection=True)


    #In the function, we are passing the floatFields, not their values.
    #So if we want to query the value before running the script, we need to
    #use the floatField cmds with the "query" flag


    extrScale = cmds.floatField(extrScaleField, q=1, v=1)
    extrDist = cmds.floatField(extrDistField, q=1, v=1)

    for i in range(len(myObjectLt)):
        numFaces = cmds.polyEvaluate(face=True)
        item = myObjectLt[i] + ".f[:]"
        cmds.select(clear=True)
        cmds.select(item, replace=True)

        #extrude by scale
        cmds.polyExtrudeFacet(constructionHistory=True, keepFacesTogether=False, localScaleX=extrScale, localScaleY=extrScale, localScaleZ=extrScale)
        selFaces = cmds.ls(selection=True)
        cmds.delete(selFaces)

        #extrude by height
        cmds.select(item, replace=True)
        cmds.polyExtrudeFacet(constructionHistory=True, keepFacesTogether=True, localTranslateZ=extrDist)

def extrWindow():
    """Creates the user interface UI for the user input of the extrusion scale and height"""
    windowID = "superExtrWindow"

    if cmds.window(windowID, exists=True):
        cmds.deleteUI(windowID)

    cmds.window(windowID, title="SuperExtrude", sizeable=False, resizeToFitChildren=True)
    cmds.rowColumnLayout(numberOfColumns=2, columnWidth=[(1,120),(2,120)], columnOffset=[1,"right",3])

    cmds.text(label="Extrusion Scale:")

    # There were an error here, replace 'text' with 'value'
    # to give your floatField a default value on its creation

    extrScaleVal = cmds.floatField(value=0.9)
    cmds.text(label="Extrusion Height:")
    extrDistVal = cmds.floatField(value=-0.3)
    cmds.separator(height=10, style="none")
    cmds.separator(height=10, style="none")
    cmds.separator(height=10, style="none")

    # As said above, use the partial function to pass your arguments in the function
    # Here, the arguments are the floatFields names, so we can then query their value
    # everytime we will press the button.

    cmds.button(label="Apply", command=partial(superExtrude,extrScaleVal, extrDistVal))
    cmds.showWindow(windowID)

extrWindow()



回答2:


cmds.button(label="Apply", command=superExtrude(extrScaleVal, extrDistVal))

This line calls superExtrude and assigns its return value to command. Since superExtrude doesn't return anything, the button effectively has a commnand of None.

Perhaps you meant to have superExtrude get called when the button is clicked, in which case you ought to wrap it in a lambda to prevent it from being called immediately:

cmds.button(label="Apply", command=lambda *args: superExtrude(extrScaleVal, extrDistVal))



回答3:


St4rb0y

First, your floatField calls (lines 33, 35) are using an invalid flag, 'text'. You probably mean to use 'value', so change both lines.

extrScaleVal = cmds.floatField(v=0.9)
extrDistVal = cmds.floatField(v=-0.3)

Secondly, when building UI control types, the 'command' flag seeks a string, so you have to wrap the command and it's arguments in quotation:

cmds.button(label="Apply", command='superExtrude(extrScaleVal, extrDistVal)')

Change those three lines and it should all work fine.

Tips:

To comment a single line of code, use # instead of enclosing the entire line in triple single quotes. The use of triple quotes is more handy for commenting out many lines of code.

Another tip for control command flags: You can define a string variable to pass commands, and use the variable instead of the string directly. This trick will come in handy when building dynamic controls, ie, assembling commands based on user selections:

comStr = "superExtrude(extrScaleVal, extrDistVal)"
cmds.button(label="Apply", command=comStr)



回答4:


so i switched everything to pymel which is what you should be learning in. cmds is garbage. take the time to look at the differences between yours and mine. scripts like these are what help you to get started. if any further explanation is needed let me know.

do this td a favor and learn pymel

pymel online docs = http://download.autodesk.com/global/docs/maya2014/en_us/PyMel/

import pymel.core as pm
def superExtrude(*args):
    """Loops through a list of selected meshes and extrudes all of the mesh faces to produce a polygon frame, based on existing mesh tesselations"""
    #pymel uses python classes to make things easier
    #its ok to not understand what a class is but just think of it the same as if you were to add an attribute to a polycube. 
    #your code variable now has attributes 

    #so with that pymel ls returns a list of PyNodes that correspond to the objects
    #cmds ls returns a list of strings which is very unuseful
    #if you look at the help docs you can find most of whats available
    myObjectLt = pm.ls(selection=True)


    for i in myObjectLt:
        #instead of cycling through by a number were gonna cycle through the list itself
        #i is now the item in the list

        #its unnecessary to select the objects because we can specify it in the polyExtrude
        #cmds.select(item,  replace=True)

        #the extrude commands selects things but im not sure what your trying to achive here by seperating
        #the scale extrude and translate extrude
        pm.select(cl=True)



        #the way poly objects wrok is that you have a transform node and a shape node
        # if you graph it in the hypershade you'll see the two nodes
        #the faces are part of the shape node i like accessing things by this node but just know you can do it like this
        #i.f  <-- f is your attribute and i is the item
        #using i.getShape() returns the shape node

        # http://download.autodesk.com/global/docs/maya2014/en_us/PyMel/generated/classes/pymel.core.uitypes/pymel.core.uitypes.FloatField.html?highlight=floatfield#pymel.core.uitypes.FloatField
        #since were using pymel the extrScaleVal has function that lets you get the value
        thisScale = extrScaleVal.getValue()


        pm.polyExtrudeFacet(i.getShape().f, constructionHistory=True, keepFacesTogether=False, localScaleX=thisScale, localScaleY=thisScale, localScaleZ=thisScale)
        #selFaces = cmds.ls(selection=True)
        pm.delete()

        #same as before
        thisDist = extrDistVal.getValue()
        #extrude by height
        pm.polyExtrudeFacet(i.getShape().f, constructionHistory=True, keepFacesTogether=True, localTranslateZ=thisDist)

def extrWindow():
    #global is a way to transfer variables from function to function the way you had it
    # you would have had to query the value from your parameters in superExtrude
    #instead do this
    global extrScaleVal, extrDistVal
    #which will makes these parameters to the other function


    """Creates the user interface UI for the user input of the extrusion scale and height"""
    windowID = "superExtrWindow"

    #instead of having a query run just use try except
    #which will just go to except when the try fails
    try:
        pm.deleteUI(windowID)
    except:
        pass

    pm.window(windowID, title="SuperExtrude", sizeable=False, resizeToFitChildren=True)
    pm.rowColumnLayout(numberOfColumns=2, columnWidth=[(1,120),(2,120)], columnOffset=[1,"right",3])

    pm.text(label="Extrusion Scale:")
    extrScaleVal = pm.floatField(v=0.9)
    pm.text(label="Extrusion Height:")
    extrDistVal = pm.floatField(v=-0.3)
    pm.separator(height=10, style="none")
    pm.separator(height=10, style="none")
    pm.separator(height=10, style="none")

    pm.button(label="Apply", c=superExtrude)
    pm.showWindow()

extrWindow()


来源:https://stackoverflow.com/questions/24616757/maya-python-cmds-button-with-ui-passing-variables-and-calling-a-function

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!