Pymel:删除空组后如何关闭 For 循环?

Pymel: How do I close For loop after deleting null groups?

在我继续研究 For 循环的过程中:我 运行 遇到了一些烦人的错误。问题是脚本完全符合我的要求。它删除了演示关节下的 null 组:但与我为重命名所做的其他循环不同,后者可以使用 cmds.ls 命令中的转换标志关闭:cmds.listRelatives 不允许关闭循环的转换标志。您 运行 脚本只需单击 Build Examples 然后点击 Delete Waste Groups

我已经根据 Maya 文档尝试了每个标志:但似乎没有任何东西可以关闭循环。我不知道我是否需要另一个变量,或者一些标志的组合:或者我是否使用了错误的措辞类型:但理想情况下,我希望这个脚本做的只是关闭循环,这样我就不会得到错误 Error: No object matches name: curve

'''
import DS_wasteGroup_cleanerDemo
reload (DS_wasteGroup_cleanerDemo)
DS_wasteGroup_cleanerDemo.gui()
'''

import re
import maya.cmds as cmds
import maya.mel as mel

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

myWindow = cmds.window("renameWin",t='DS_wasteGroup_cleanerDemo',w=200, h=500, toolbox=True)
column = cmds.columnLayout(adj=True)

def gui():

    cmds.button( label="Build Examples", c = buildExamples)
    cmds.separator( w=200, h=3)
    cmds.button( label="Delete Waste Groups", c = deleteWasteGrp)
    cmds.separator( w=200, h=9)

    cmds.setParent('..')
    cmds.showWindow(myWindow)

def buildExamples(*args):

    cmds.group(n='exampleGroup1',world=True,empty=True)
    cmds.joint(n='demoJoint1')
    cmds.group(n='curve1',world=True,empty=True)
    cmds.parent('curve1','demoJoint1')

    cmds.joint(n='demoJoint2')
    cmds.parent('demoJoint2','exampleGroup1')
    cmds.group(n='curve2',world=True,empty=True)
    cmds.parent('curve2','demoJoint2')

    cmds.joint(n='demoJoint3')
    cmds.parent('demoJoint3','exampleGroup1')
    cmds.group(n='curve3',world=True,empty=True)
    cmds.parent('curve3','demoJoint3')

    cmds.joint(n='demoJoint4')
    cmds.parent('demoJoint4','exampleGroup1')
    cmds.group(n='curve4',world=True,empty=True)
    cmds.parent('curve4','demoJoint4')

    cmds.joint(n='demoJoint5')
    cmds.parent('demoJoint5','exampleGroup1')
    cmds.group(n='curve5',world=True,empty=True)
    cmds.parent('curve5','demoJoint5')


def deleteWasteGrp(*args):
    grpList = cmds.listRelatives('demoJoint*',p=True,f=True)
    for name in grpList:
        print(grpList)
        cmds.delete('curve*')

如果我发布的是简单的问题,我深表歉意。我确实编写了 Python 脚本来自动执行装配中最繁琐的任务:但我的知识只是中等水平。我想了解更多 python,这样我的脚本就不会那么笨拙和强制:以及我需要它们更适应各种类型的角色这一事实:所以任何使这一切变得愚蠢的资源也将是赞赏。感谢您的帮助。

错误是正确的,因为 for 循环第一次执行时,所有 "curve" 对象都被删除,然后在下一次迭代中,相同的命令找不到任何曲线对象,因为它们已经被删除.如果将删除命令放在 for 循环之外,错误应该会消失。

我觉得你对整个过程的理解有点不对,如果你有兴趣,我很乐意详细说明,但现在这里有一个针对你的循环情况的修复:

def deleteWasteGrp(*args):    
    curveList = cmds.ls('curve*',transforms=True)
    try:
        cmds.delete(curveList)
        print('Deleted the following objects: {}'.format(curveList))
    except Exception as e:
        cmds.warning('Cleanup failed: {}'.format(e))

cmds.delete 方法接受一个列表参数,在您的情况下这是完成工作的最简单方法。请记住,当您删除父对象时,您也会删除其子对象,因此根据您的情况删除对象可以是特定于顺序的。

在 try/except 子句中抛出任何 "likely to fail" 调用通常是一个好主意,因为它可以让您优雅地处理错误。但是要小心,不要压制它并继续前进——你至少需要充分提醒用户。

最后,如果您 运行 方法不止一次,您的 buildExamples 方法很可能会失败。因为您是通过字符串文字(硬编码名称)来寻址对象,而不是跟踪它们的实际名称(和完整路径)。您最终可能会看到此错误:

# Error: ValueError: file <maya console> line ??: More than one object matches name: demoJoint1 # 

编辑:根据要求进行了一些阐述

命令 cmds.groupcmds.joint return 一个字符串值,指示创建的对象的实际名称(在创建模式下)。存储此值通常是个好主意,以防 Maya 决定为您的对象命名与您期望的略有不同,通常是在存在命名冲突时。例如:

print cmds.group(name='test', world=True, empty=True)
# Returns: test

print cmds.group(name='test', world=True, empty=True)
# Returns: test1

如何在创建对象时捕获对象名称的示例。我已将您的五个相同(大概)调用连接起来以在此循环中创建关节和曲线:

import maya.cmds as cmds

topGroupName = 'exampleGroup'
actualTopGroupName = None

# Create top level group
actualTopGroupName = cmds.group(n=topGroupName, world=True, empty=True)

# Loop through 5 times and do the following:
for i in range(5):
    # PS: hash character in name indicates "next available number"
    cmds.select(clear=True)
    jnt = cmds.joint(n='demoJoint#') 
    crv = cmds.group(n='curve#',world=True,empty=True)
    cmds.parent(crv, jnt)
    cmds.parent(jnt, actualTopGroupName)

如何使用 cmds.ls 缩小要搜索的对象的示例:

topGroupName = 'exampleGroup'
print cmds.ls('|{}*|*|curve*'.format(topGroupName)) 
# Returns: [u'curve1', u'curve2', u'curve3', u'curve4', u'curve5']

# The string .format() expression is just a dynamic way of writing this:
# |exampleGroup*|*|curve*

垂直管道 (|) 表示层次结构中的级别,类似于斜杠 (/) 在 URL 中的工作方式。而asterisks/wildcards(*)表示"any character, or none".

希望这对您有所帮助。

老实说,我会采用一种完全不同的方法,因为您正在对所有可能很容易导致灾难的东西进行硬编码。当我指的是硬编码时,我的意思是您正在尝试将 "demoJoint2" 作为对象的父级。这很糟糕,因为你为什么假设 "demoJoint2" 甚至存在?如果您使用已经存在的特定名称创建对象,Maya 将自动重命名新对象,现在您会立即引用错误的对象!相反,当你创建你的对象时,在一个变量中捕获它们的名字然后使用它,否则你会不断地搬起石头砸自己的脚。

这是相同的脚本,但我会尝试使用这种方法:

import maya.cmds as cmds


def gui():
    if cmds.window("renameWin", exists=True):
        cmds.deleteUI("renameWin", window=True)

    myWindow = cmds.window("renameWin", t="DS_wasteGroup_cleanerDemo", w=200, h=500, toolbox=True)
    column = cmds.columnLayout(adj=True)

    cmds.button(label="Build Examples", c=buildExamples)
    cmds.separator(w=200, h=3)
    cmds.button(label="Delete Waste Groups", c=deleteWasteGrp)
    cmds.separator(w=200, h=9)

    cmds.setParent("..")
    cmds.showWindow(myWindow)


def buildExamples(*args):
    root = cmds.group(n="exampleGroup1", world=True, empty=True)

    for i in range(5):  # Loop to the amount of joints you want to create.
        jnt = cmds.createNode("joint", name="demoJoint" + str(i + 1))  # Use `i` to help name the object.
        jnt = cmds.parent(jnt, root)[0]  # Parenting changes its long name, so recapture the joint in a variable.
        crv = cmds.group(n="curve" + str(i + 1), world=True, empty=True)  # Create empty group.
        cmds.parent(crv, jnt)  # Parent curve to joint.


def deleteWasteGrp(*args):
    jnts = cmds.ls("demoJoint*", long=True, type="joint")  # Get all `demoJoints`.
    children = cmds.listRelatives(jnts, f=True, children=True, type="transform") or []  # Get all of their children, and only get transform types.
    curves = [obj for obj in children if obj.split("|")[-1].startswith("curve")]  # Don't assume we got the right objects. Run a final loop to collect any object that starts with `curve`. Need to use split as we're looping through long names but need to check its short name.
    if curves:  # `cmds.delete` will error if this list is empty, so don't assume.
        cmds.delete(curves)  # Delete all curves at once.


gui()

现在我可以随心所欲地点击构建按钮,并且在按下删除按钮时删除所有曲线。

更多注意事项:

请注意 buildExamples 我正在使用一个循环来创建所有对象,而不是重复使用执行相同操作的冗余代码。你甚至可以在你的 gui 中有一个旋转框来定义它现在创建了多少个关节,而以前是不可能的,因为计数是硬编码的。

cmds.listRelatives 是否有办法通过设置参数 type="transform" 进行变换来过滤对象。事实上,您会看到许多命令都有相同的参数(再次开始检查文档)。

cmds.listRelatives('demoJoint*',p=True,f=True) 正在获取关节的父项,而不是其子项。文档清楚地说明了这一点。

运行 cmds.delete('curve*') 将删除名称以 curve 开头的 ALL 个对象,并且由于您是 运行一个循环,它试图多次执行此操作。

maya.cmds 不是 pymel。有一个名为 pymel.

的完整独立模块

如果您不确定代码的任何部分,请尝试添加 print 语句以查看它在做什么。