Вызов функции из класса пользовательского интерфейса в Maya, приводящий к ошибке, не связанной с типом - PullRequest
0 голосов
/ 11 декабря 2019

Я создаю пользовательский интерфейс панели инструментов, используя python в Maya, и продолжаю получать ошибку Nontype, когда я вызываю одну из импортированных функций. Вот сценарий для панели инструментов:

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 () работает нормально, пока я его вызываюсам по себе, используя формат RandomScatter ([a, b, c, d, e, f]), но когда я пытаюсь назвать его Toolbox (), я получаю строку «Scatter.py 21: объект NoneType не имеет атрибута»' getitem ' "как ошибка. Это также происходит, когда я пытаюсь использовать команду intField () вместо textField (). Окно пользовательского интерфейса строится просто отлично;ошибка возникает только после ввода ввода в текстовое поле и нажатия кнопки, которая должна вызывать RandomScatter (). Похоже, что ввод не попадает в список MinAndMax, поэтому, когда он достигает «cmds.move ((random.randint (MinAndMax [0]»), он не может найти ничего для помещения в слот MinAndMax [0]или любой из слотов после этого, но я не могу понять, почему. У кого-нибудь есть совет?

Ответы [ 2 ]

1 голос
/ 03 января 2020

Как написано self.MinAndMax - текстовое поле;даже если вы получите значение из него, это будет строка, и вы не сможете проиндексировать ее, чтобы получить отдельные элементы - и ваша индексация будет сброшена, если любое из чисел будет отрицательным или будет иметь десятичные дроби. Ленивое решение - использовать FloatFieldGrp, который позволяет вам иметь 2-4 цифровых входа. Немного раздражает сразу получить все значения (посмотрите, как это делается ниже), но это позволит избежать многих проблем при попытке разобрать текстовое поле.

Кроме того, эта строка не имеет смысла в контексте:

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

Вы не видите ошибку, потому что она терпит неудачу в предыдущей строке, но первый аргумент должен бытьимя существующего intField.

В любом случае, я бы немного реорганизовал это, чтобы исключить разбор аргументов из функции разброса, чтобы вы могли отделить рабочую логику от логики разбора пользовательского интерфейса. Намного легче будет определить, где что-то пошло не так:

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

Моя версия немного меняет вашу логику - вы дублировали свой список выбора, что приводило к тому, что количество элементоврасти в геометрической прогрессии (поскольку каждое дублирование также дублирует предыдущие дубликаты). Я не уверен, соответствует ли это вашему намерению или нет.

Вы можете избежать лишних лямбд, добавив *_ в реальный обратный вызов кнопки;это незначительный раздражитель майя, что у кнопок всегда есть этот бесполезный первый аргумент.

Кроме того, я бы постарался не выполнять импорт внутри тел функций. Если импортированный модуль недоступен, лучше знать, когда этот файл импортируется, а не только когда пользователь нажимает кнопку - гораздо легче обнаружить отсутствующий модуль, если выполнить все операции импорта в блоке вверху. .

1 голос
/ 12 декабря 2019

Я не проверял ваш код и не прочитал его полностью, но уже могу сказать, что ваше странное использование лямбды не имеет никакого смысла.

lambda *args: self.ControlBTN()

эта лямбда-функция выполняет себя.ControlBTN во время определения кнопки cmds.button и предоставить ему функцию, которая возвращает 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)
...

Это должно помочь

удачи

...