【问题标题】:Maya Python: cmds.button( ) with UI passing variables and calling a function?Maya Python:带有 UI 传递变量和调用函数的 cmds.button()?
【发布时间】:2014-07-07 17:55:03
【问题描述】:

首先,这似乎是学习更多编程知识的好地方。 我编写了一个 maya python 脚本,这两个函数都可以工作,但是我无法让 UI 按钮调用 superExtrude() 函数。 第一个函数进行几何网格操作,第二个函数应该为用户输入生成 UI:

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()

我对 python 和 maya 脚本还很陌生,因此非常感谢任何帮助。 :)

【问题讨论】:

  • 从 UI 对象 here 调用函数的不同方式的一些背景知识

标签: python maya pymel


【解决方案1】:

我不确定这是否是您想要的答案,但您必须了解 Maya“命令”标志:

  • 如果要在按钮调用中放入函数,则需要传入不带任何参数的函数名(例如:command = myFunction)(去掉结尾括号“()”)

  • 在您的函数中,您需要添加一个“*args”,因为 Maya 按钮总是传递一个参数(我认为它是“False”)(例如:def myFunction(customArg1, customArg2, *args))

  • 如果要在按钮信号中传递参数,则需要使用 functools 模块中的部分函数(来自 functools import partial)并像这样使用它: cmds.button(command = partial(myFunction, arg1, arg2, kwarg1=value1, kwarg2=value2))

还有一点,关于 pymel 和 cmds……这可能是一个永无止境的故事,但 pymel 并不是万能的……当您必须处理大量信息(例如在网格上获取顶点列表)时,pymel可能比简单的 Maya 命令慢 40 倍。 它有它的优点和缺点......如果你刚开始使用 python,我不建议你现在进入 pymel。 熟悉语法和命令,当你没问题时,切换到 pymel(这在你处理对象创建时非常有用)

希望这有帮助, 干杯

编辑:

根据您的第一篇文章,您需要更改代码以使其正常工作:

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()

【讨论】:

  • 非常感谢!你的绝对是最好的答案。它适用于您的更改,但是如果您能向我解释“extrScale = cmds.floatField(extrScaleField, q=1, v=1)” 是如何获取值的,我会很高兴,因为变量字段名称是' 甚至与 UI 功能中的不同。我很困惑!
  • 当你创建你的 floatFields 时,你在一个变量中创建它们。因此,您确定 var 将存储您的字段的名称。不管名字会是什么。如果它的“floatfield354”或类似的东西,我们不在乎。然后,在脚本中,我们给它这个变量。最后,我们只需要使用带有 var 作为 floatField 名称的查询命令。
  • 如果你感到困惑,我想,这可能是因为在 extrWindow() 和 superExtrude() 函数中都声明了“extrScale”和“extrDistVal”变量。但是由于它们中的每一个都在不同的函数中声明,它们不会覆盖自己。一个属于 extrWindow(),另一个属于 superExtrude()。在 extrWindow() 中,“extrScaleVal 和 extrDistVal”是浮点字段的名称。在 superExtrude() 中,“extrScaleField 和 extrDistField”是获取 floatfields 名称的参数,“extrScaleVal 和 extrDistVal”是查询到的 floatFields 值。有意义吗?
  • 非常感谢您的大力帮助。整个 Maya UI 的东西现在对我来说更有意义了。谢谢!
【解决方案2】:
cmds.button(label="Apply", command=superExtrude(extrScaleVal, extrDistVal))

此行调用superExtrude 并将其返回值分配给command。由于superExtrude 不返回任何内容,因此该按钮实际上具有None 的命令。

也许您打算在单击按钮时调用 superExtrude,在这种情况下,您应该将其包装在 lambda 中以防止立即调用它:

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

【讨论】:

  • 当我尝试实现 lamdba 命令时,我得到:# 错误:() 没有参数(1 个给定)# 知道为什么吗?
  • 糟糕,我猜回调传递了一些我不知道的参数。我已经编辑了我的答案。
【解决方案3】:

St4rb0y

首先,您的 floatField 调用(第 33、35 行)使用了无效标志“text”。您的意思可能是使用“值”,因此更改这两行。

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

其次,在构建 UI 控件类型时,'command' 标志会查找字符串,因此您必须将命令及其参数用引号括起来:

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

更改这三行,它应该都可以正常工作。

提示:

要注释单行代码,请使用 # 而不是将整行括在三个单引号中。使用三引号更方便注释掉多行代码。

控制命令标志的另一个提示:您可以定义一个字符串变量来传递命令,并直接使用该变量而不是字符串。这个技巧在构建动态控件时会派上用场,即根据用户选择组装命令:

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

【讨论】:

  • “文本”标志是我之前使用的“cmds.textField”的剩余部分。感谢您看到它和其他提示。你知道为什么我在使用'cmds.floatField'和'cmds.intField'时会出现以下错误:'#range() integer end argument expected, got unicode.#' 出于某种原因,字段输入似乎将 unicode 传递给 python 代码。不过,它需要整数(或浮点数)来表示随机范围。你知道如何解决这个问题吗?我尝试将文本字段包装到“int(cmds.[...]Field)”或“float(cmds.[...]Field)”中,但这会返回转换错误。
【解决方案4】:

所以我将所有内容都切换到了 pymel,这是您应该学习的内容。cmds 是垃圾。 花点时间看看你和我的区别。像这样的脚本可以帮助您入门。如果需要任何进一步的解释,请告诉我。

帮个忙,学习 pymel

pymel 在线文档 = 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()

【讨论】:

  • 感谢您的精彩评论。 pyMel 将是我学习雷达上的下一个目标。不过,困扰我的一件事是它与其他开箱即用的 Maya 不兼容,这意味着您通常必须先安装它。
猜你喜欢
  • 1970-01-01
  • 2015-04-27
  • 1970-01-01
  • 1970-01-01
  • 2020-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-10
相关资源
最近更新 更多