【问题标题】:Calling function from UI class in maya resulting in nonetype error从 Maya 中的 UI 类调用函数导致非类型错误
【发布时间】:2020-04-04 23:36:58
【问题描述】:

我正在 Maya 中使用 python 构建一个工具箱 UI,当我调用其中一个导入的函数时,我不断收到 Nonetype 错误。这是工具箱的脚本:

class Toolbox():

    import maya.cmds as cmds


    def __init__(self):

        self.window_name = "mlToolbox"
    def create(self): 
        self.delete()
        self.window_name = cmds.window(self.window_name)
        self.m_column = cmds.columnLayout(p = self.window_name, adj = True)
        cmds.button(p=self.m_column,label = 'MyButton', c=lambda *arg: cmds.polySphere(r = 2))



        cmds.button(p=self.m_column, label = 'Make_Control', command = lambda *args: self.ControlBTN())

        cmds.button(p=self.m_column, label = 'Find Center of All Selected', command = lambda *args: self.CenterBTN())

        cmds.button(p=self.m_column, label = 'Find Center of Each Selected Object', command = lambda *args: self.IndiCenterBTN())

        self.colorname = cmds.textField(placeholderText = 'Enter color name...')
        cmds.button(p=self.m_column, label = 'ChangeColor', command = lambda *args: self.colorBtn())


        self.MinAndMax = cmds.textField()
        cmds.button(p=self.m_column, label = 'Random Scatter', command = lambda *args: self.ScatterBTN())

        cmds.showWindow(self.window_name)

        cmds.button(p=self.m_column, label = 'Select Everything', command = lambda *args: self.selectBTN())

    def CenterBTN(self):
        import CenterSelected
        CenterSelected.Locator()

    def ScatterBTN(self):
        import Scatter
        value = cmds.textField(self.MinAndMax, q=True)
        Scatter.RandomScatter(value)
        cmds.intField(self.moveMin, self.moveMax, self.rotMin, self.rotMax, self.scaleMin, self.scaleMax, e=True, text='')


    def IndiCenterBTN(self):
        import ManySelected
        ManySelected.LocatorMany()

    def colorBtn(self):
        import ColorControl
        value = cmds.textField(self.colorname, q=True, text = True)
        ColorControl.colorControl(value)
        cmds.textField(self.colorname, e=True, text='')

    def selectBTN(self): 
        import tools
        tools.selectAll()

    def delete(self): 
        if cmds.window(self.window_name, exists=True):
            cmds.deleteUI(self.window_name)

    def ControlBTN(self):

        import CreateControl
        CreateControl.createControl()

myTool = Toolbox()    

myTool.create()   

这是我遇到问题的功能:

def RandomScatter(MinAndMax):

    import random

    import maya.cmds as cmds



    Stuff = cmds.ls(sl=True)

    i=0



    for i in range(random.randint(1,100)):

        Stuff.append(cmds.duplicate(Stuff))

        cmds.move( (random.randint(MinAndMax[0], MinAndMax[1])), (random.randint(MinAndMax[0], MinAndMax[1])), (random.randint(MinAndMax[0], MinAndMax[1])), Stuff[i], absolute=True ) 

        cmds.rotate( (random.randint(MinAndMax[2], MinAndMax[3])), (random.randint(MinAndMax[2], MinAndMax[3])), (random.randint(MinAndMax[2], MinAndMax[3])), Stuff[i], absolute=True )

        cmds.scale( (random.randint(MinAndMax[4], MinAndMax[5])), (random.randint(MinAndMax[4], MinAndMax[5])), (random.randint(MinAndMax[4], MinAndMax[5])), Stuff[i], absolute=True )

        i = i+1

只要我使用 RandomScatter([a, b, c, d, e, f]) 格式自己调用它,RandomScatter() 就可以正常工作,但是当我尝试调用它 Toolbox() 时,我得到了“Scatter.py 第 21 行:'NoneType' 对象没有属性 'getitem'”作为错误。当我尝试使用 intField() 命令而不是 textField() 时也会发生这种情况。 UI 窗口构建得很好;该错误仅在我在文本字段中输入输入并按下应该调用 RandomScatter() 的按钮后发生。似乎输入没有进入 MinAndMax 列表,所以当它到达“cmds.move( (random.randint(MinAndMax[0]”) 时,它找不到任何东西可以放入 MinAndMax[0] 槽,或之后的任何插槽,但我不知道为什么。有人有什么建议吗?

【问题讨论】:

  • 您没有指定从textField 查询的内容。我猜你想阅读它的文字,所以你应该使用cmds.textField(self.MinAndMax, q=True, text=True)
  • lambda *args 可能只是吞下按钮回调中无用的第一个参数的简写

标签: python user-interface maya


【解决方案1】:

我没有测试你的代码,也没有完全阅读它,但我已经可以说你奇怪的“lambda”用法没有任何意义。

lambda *args: self.ControlBTN()

这个 lambda 在 cmds.button 定义期间执行 self.ControlBTN 并为其提供一个返回 None 的函数。 喜欢这样做:

self.ControlBTN()
function = def func(): return None
cmds.button(p=self.m_column, label = 'Make_Control', command=function)

我建议您重新阅读有关“python lambda”的文档。

替换为:

cmds.button(p=self.m_column, label = 'Make_Control', command=self.ControlBTN)
...
def ControlBTN(self, *args)
...

应该有帮助

祝你好运

【讨论】:

  • 对我来说,lambda 的使用似乎是正确的,即使您的替代方法也可以正常工作。
【解决方案2】:

self.MinAndMax 是一个文本字段;即使您从中获取值,它也将是一个字符串,您将无法对其进行索引以获取各个项目 - 如果任何数字为负数或有小数,您的索引将被丢弃。懒惰的解决方案是使用FloatFieldGrp,它可以让您有 2-4 个数字输入。一次获取所有值有点烦人(请参阅下面的方法),但它会避免尝试解析文本字段时出现许多问题。

另外,这行在上下文中没有意义:

    cmds.intField(self.moveMin, self.moveMax, self.rotMin, self.rotMax, self.scaleMin, self.scaleMax, e=True, text='')

您没有看到错误,因为它在上一行中失败了,但第一个参数应该是现有 intField 的名称。

在任何情况下,我都会对此进行一些重构,以使参数解析不受 scatter 函数的影响,这样您就可以将工作逻辑与 UI 解析逻辑分开。这将使发现事情偏离轨道的地方变得更加容易:

import random
import maya.cmds as cmds

class TestGUI(object):

    def __init__(self):
        self.window = cmds.window()
        self.layout = cmds.rowLayout(nc=3)
        self.min_xyz = cmds.floatFieldGrp( numberOfFields=3, label='min', value1=-10, value2=-10, value3=-10 )
        self.max_xyz= cmds.floatFieldGrp( numberOfFields=3, label='min', value1=10, value2=10, value3=10 )
        cmds.button(label='scatter', c = self.scatter)
        cmds.showWindow(self.window)

    def scatter(self, *_):
        selected = cmds.ls(sl=True)
        if not selected:
            cmds.warning("select something")
            return

        min_xyz = (
            cmds.floatFieldGrp(self.min_xyz, q=True, v1=True),
            cmds.floatFieldGrp(self.min_xyz, q=True, v2=True),
            cmds.floatFieldGrp(self.min_xyz, q=True, v3=True)
        )

       max_xyz = (
            cmds.floatFieldGrp(self.max_xyz, q=True, v1=True),
            cmds.floatFieldGrp(self.max_xyz, q=True, v2=True),
            cmds.floatFieldGrp(self.max_xyz, q=True, v3=True)
        )

        print "scatter settings:", min_xyz, max_xyz
        rand_scatter(selected, min_xyz, max_xyz)



def rand_scatter(selection, min_xyz, max_xyz):

    dupe_count = random.randint(1, 10)
    duplicates = [cmds.duplicate(selection) for n in range(dupe_count)]

    for dupe in duplicates:
        destination = [random.randint(min_xyz[k], max_xyz[k]) for k in range(3)]
        cmds.xform(dupe, t=destination, absolute=True)
        print (dupe, destination)


t = TestGUI() # shows the window; hit 'scatter' to test

我的版本稍微改变了你的逻辑——你在复制你的选择列表,这会导致项目的数量呈指数增长(因为每个重复也会重复之前的重复)。我不确定这是否符合您的意图。

您可以通过在实际的按钮回调中包含 *_ 来避免额外的 lambda;按钮总是有那个无用的第一个参数,这是一个小的玛雅刺激。

顺便说一句,我会尽量不在函数体内进行导入。如果导入的模块不可用,最好在导入此文件时知道,而不是仅在用户单击按钮时知道 - 如果您在顶部的块中执行所有导入,则更容易发现丢失的模块.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-13
    • 2012-07-23
    • 1970-01-01
    • 2012-01-28
    • 2018-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多