在Maya中使用Pymel/Python的GUI时报运行时错误
我正在尝试制作一个图形用户界面(GUI),让用户可以通过勾选框来构建指定的多边形形状(polyShapes),并根据需要调整一些属性(通过滑块设置)。每当选择一个勾选框时,其他的勾选框会被取消选择,同时一些用户不需要的属性会变成灰色,无法使用。
我在处理每个勾选框被选中时应该执行的功能上遇到了困难。当勾选框被选中,属性设置好后,点击创建按钮,整个过程是正常的(结果也符合我的预期),但除了最后一个勾选框外,其他的都会出现以下错误:
RuntimeError: Object 'window1|formLayout46|checkBox3' not found. #
有人告诉我,这个错误是因为函数在运行旧版本的窗口,建议我把滑块等作为参数传递给函数,这样可以解决问题。然而,这并没有解决我的问题,当然在勾选框还没创建之前,我也无法将它们作为参数传递,正如下面的代码所示。此外,这也没有解释为什么最后一个勾选框(checkBoxCylinder)可以正常工作——我猜测这是因为在它之前,所有的东西都已经创建好了。
如果有人能给出建议或解释,我将非常感激,因为我现在感觉自己在原地打转。抱歉下面的代码有点长,我无法只用一部分,因为它们都是相互关联的!!
import pymel.core as pm
class MakeLightDome(object):
def __init__(self):
sel = []
def checkSelection(self):
sel = pm.ls(selection = True)
length = len(sel)
#Check Selection
if length == 0:
print "Please create a PolySphere."
def show():
global win
try:
win.delete()
except:
pass
win = pm.window(title = "Dome Generator")
mainLayout = pm.verticalLayout()
mainLayout.setHeight(400)
def buttonPressed(*args):
#Create Sphere
if checkBoxSphere.getValue():
radiusSet = rSlider.getValue()
xSubDivs = xSubDSlider.getValue()
ySubDivs = ySubDSlider.getValue()
pm.polySphere(r = radiusSet, sx = xSubDivs, sy = ySubDivs)
#Move on to create lights
win.delete()
if checkBoxCube.getValue():
#CreateCube
xDime = xSlider.getValue()
yDime = ySlider.getValue()
zDime = zSlider.getValue()
xSubDivs = xSubDSlider.getValue()
ySubDivs = ySubDSlider.getValue()
zSubDivs = zSubDSlider.getValue()
pm.polyCube(w = xDime, h = yDime, d = zDime, sx = xSubDivs, sy = ySubDivs, sz = zSubDivs)
#Move on to create lights
win.delete()
if checkBoxCone.getValue():
#Create Cone
yDime = ySlider.getValue()
radiusSet = rSlider.getValue()
xSubDivs = xSubDSlider.getValue()
ySubDivs = ySubDSlider.getValue()
zSubDivs = zSubDSlider.getValue()
pm.polyCone(h = yDime, r = radiusSet, sx = xSubDivs, sy = ySubDivs, sz = zSubDivs)
#Move on to create lights
win.delete()
if checkBoxCylinder.getValue():
#Create Cylinder
yDime = ySlider.getValue()
radiusSet = rSlider.getValue()
xSubDivs = xSubDSlider.getValue()
ySubDivs = ySubDSlider.getValue()
zSubDivs = zSubDSlider.getValue()
pm.polyCylinder(h = yDime, r = radiusSet, sx = xSubDivs, sy = ySubDivs, sz = zSubDivs)
#Move on to create lights
win.delete()
def sphereBoxChecked(*args):
xSlider = args[0]
ySlider = args[1]
zSlider = args[2]
rSlider = args[3]
xSubDSlider = args[4]
ySubDSlider = args[5]
zSubDSlider = args[6]
checkBoxCube = args[7]
checkBoxCone = args[8]
checkBoxCylinder = args[9]
#Checkbox off
checkBoxCube.setValue(False)
checkBoxCone.setValue(False)
checkBoxCylinder.setValue(False)
#Slider enable
xSlider.setValue(en = False)
ySlider.setValue(en = False)
zSlider.setValue(en = False)
rSlider.setValue(5, en = True)
xSubDSlider.setValue(10, en = True)
ySubDSlider.setValue(10, en = True)
zSubDSlider.setValue(en = False)
def cubeBoxChecked(*args):
xSlider = args[0]
ySlider = args[1]
zSlider = args[2]
rSlider = args[3]
xSubDSlider = args[4]
ySubDSlider = args[5]
zSubDSlider = args[6]
checkBoxSphere = args[7]
checkBoxCone = args[8]
checkBoxCylinder = args[9]
#Checkbox off
checkBoxSphere.setValue(False)
checkBoxCone.setValue(False)
checkBoxCylinder.setValue(False)
#Slider enable
xSlider.setValue(10, en = True)
ySlider.setValue(10, en = True)
zSlider.setValue(10, en = True)
rSlider.setValue(en = False)
xSubDSlider.setValue(5, en = True)
ySubDSlider.setValue(5, en = True)
zSubDSlider.setValue(5, en = True)
def coneBoxChecked(*args):
xSlider = args[0]
ySlider = args[1]
zSlider = args[2]
rSlider = args[3]
xSubDSlider = args[4]
ySubDSlider = args[5]
zSubDSlider = args[6]
checkBoxSphere = args[7]
checkBoxCube = args[8]
checkBoxCylinder = args[9]
#Checkbox off
checkBoxSphere.setValue(False)
checkBoxCube.setValue(False)
checkBoxCylinder.setValue(False)
#Slider enable
xSlider.setValue(en = False)
ySlider.setValue(10, en = True)
zSlider.setValue(en = False)
rSlider.setValue(5, en = True)
xSubDSlider.setValue(15, en = True)
ySubDSlider.setValue(10, en = True)
zSubDSlider.setValue(5, en = True)
def cylinderBoxChecked(*args):
#Checkbox off
checkBoxSphere.setValue(False)
checkBoxCube.setValue(False)
checkBoxCone.setValue(False)
#Slider enable
xSlider.setValue(en = False)
ySlider.setValue(15, en = True)
zSlider.setValue(en = False)
rSlider.setValue(5, en = True)
xSubDSlider.setValue(15, en = True)
ySubDSlider.setValue(5, en = True)
zSubDSlider.setValue(5, en = True)
#Slider settings
#Dimensions
xSlider = pm.floatSliderGrp(label = "x Dimension", field = True, parent = mainLayout, en = False)
xSlider.setValue(10)
ySlider = pm.floatSliderGrp(label = "y Dimension", field = True, parent = mainLayout, en = False)
ySlider.setValue(10)
zSlider = pm.floatSliderGrp(label = "z Dimension", field = True, parent = mainLayout, en = False)
zSlider.setValue(10)
rSlider = pm.floatSliderGrp(label = "Radius", field = True, parent = mainLayout, en = False)
rSlider.setValue(10)
#SubDivisions
xSubDSlider = pm.intSliderGrp(label = "x SubDivs",field = True, parent = mainLayout, en = False)
xSubDSlider.setValue(10)
ySubDSlider = pm.intSliderGrp(label = "y SubDivs", field = True, parent = mainLayout, en = False)
ySubDSlider.setValue(10)
zSubDSlider = pm.intSliderGrp(label = "z SubDivs", field = True, parent = mainLayout, en = False)
zSubDSlider.setValue(10)
#Check Box Settings
checkBoxSphere = pm.checkBox(label = "Sphere", value = False, parent = mainLayout, onc = pm.Callback(sphereBoxChecked, xSlider, ySlider, zSlider, rSlider, xSubDSlider, ySubDSlider, zSubDSlider, checkBoxCube, checkBoxCone, checkBoxCylinder))
checkBoxCube = pm.checkBox(label = "Cube", value = False, parent = mainLayout, onc = pm.Callback(cubeBoxChecked, xSlider, ySlider, zSlider, rSlider, xSubDSlider, ySubDSlider, zSubDSlider, checkBoxSphere, checkBoxCone, checkBoxCylinder))
checkBoxCone = pm.checkBox(label = "Cone", value = False, parent = mainLayout, onc = pm.Callback(coneBoxChecked, xSlider, ySlider, zSlider, rSlider, xSubDSlider, ySubDSlider, zSubDSlider, checkBoxSphere, checkBoxCube, checkBoxCylinder))
checkBoxCylinder = pm.checkBox(label = "Cylinder", value = False, parent = mainLayout, onc = pm.Callback(cylinderBoxChecked))
btn = pm.button(label = "Create", parent = mainLayout, command = pm.Callback(buttonPressed))
mainLayout.redistribute()
win.show()
show()
dome = MakeLightDome()
dome.checkSelection()
1 个回答
1
你可能不想把这个作为全局变量来用,因为这样会让你的状态管理变得复杂。通常来说,比较“正确”的做法(这里用引号是为了强调)是把图形界面(GUI)放在一个类里面,把所有的状态都存储在这个类里。这样做的好处是,你可以很清楚地知道所有的状态数据是如何和相同的控件连接在一起的。除了让代码看起来更整洁,这样还可以让你同时打开多个相同的对话框(比如,如果你需要为每个对象打开一个这样的对话框)。
下面是一个非常简单的例子。因为所有的控件(至少是你关心的那些)都包含在对话框的“self”里面,所以当你响应按钮点击时,获取所需的信息就变得非常简单。
import pymel.core as pm
class SliderDialog(object):
def __init__(self):
self.SomeSpecialData = "Hello world"
self.Window = pm.window(width = 300)
with pm.columnLayout():
self.XSlider = pm.floatSliderGrp(label = 'x', field = True)
self.YSlider = pm.floatSliderGrp(label = 'y', field = True)
self.ZSlider = pm.floatSliderGrp(label = 'z', field = True)
with pm.rowLayout(nc= 2):
self.Cancel = pm.button("cancel", width = 150, command = self.cancel_button)
self.Go = pm.button("go", width = 150, c=self.go_button)
def show(self):
self.Window.show()
def go_button(self, *_):
# your actual work goes here
print "Special Data = ", self.SomeSpecialData
x, y, z = self.XSlider.getValue(), self.YSlider.getValue(), self.ZSlider.getValue()
print "do something with XYZ (%i, %i, %i)" % (x, y, z)
def cancel_button(self, *_):
print "cancelling"
pm.deleteUI(self.Window)
SliderDialog().show()