Maya/Python:在循环生成的UI中创建唯一命令
在Autodesk Maya中,我根据用户要创建的楼层数(变量numFloors从intField中获取)动态创建UI。对于每一层,我想制作一个按钮,用于更改相机的高度以查看楼层(这是针对建筑物的)。我的问题是,我无法让viewFloor()函数知道按下哪个按钮来激活它。每次按钮都会经过最近的楼层,而不是特定的楼层 我知道为什么会发生这种情况,当创建按钮时,命令不会动态存储,因此当单击按钮时,命令会使用变量的最新实例,该实例应该是与变量numFloors相等的最后一层Maya/Python:在循环生成的UI中创建唯一命令,python,loops,user-interface,maya,autodesk,Python,Loops,User Interface,Maya,Autodesk,在Autodesk Maya中,我根据用户要创建的楼层数(变量numFloors从intField中获取)动态创建UI。对于每一层,我想制作一个按钮,用于更改相机的高度以查看楼层(这是针对建筑物的)。我的问题是,我无法让viewFloor()函数知道按下哪个按钮来激活它。每次按钮都会经过最近的楼层,而不是特定的楼层 我知道为什么会发生这种情况,当创建按钮时,命令不会动态存储,因此当单击按钮时,命令会使用变量的最新实例,该实例应该是与变量numFloors相等的最后一层 for i in rang
for i in range(0, numFloors):
floor = i
btnName = 'floor'+str(floor)+'ViewBtn'
btnLabel = "view Floor " + str(floor)
btnCmdVar = str(floor)
cmds.button(btnName, label= btnLabel, w=20, h=20, command=lambda
arg:self.viewFloor(btnCmdVar))
def viewFloor(self, arg):
print "arg = " + str(arg)
因此,当numFloors=4时,无论按下哪个楼层按钮,viewFloor都将始终向其传递4。正如我所说,我知道为什么会发生这种情况,这个代码片段只是我创建一个代码片段的最佳尝试,它将传达我正在尝试做的事情。不幸的是,我不知道如何真正做到这一点
我的一些想法是:
一些复杂的setattr和getattr设置(但我不知道如何工作)
或者是一个scriptJob,它检测按钮何时被按下,并将特定按钮的名称传递给viewFloor函数(然后我可以从字符串中提取数字以获得楼层)。但是,在Maya Python文档中,我找不到按下按钮时发生的事件或条件的任何指示。因此,我无法创建scriptJob
如果有人能为我指出正确的方向(例如我可能需要的scriptJob标志或setattr getattr设置的示例)或任何其他解决方案,我将不胜感激,因为我没有受过足够的教育,甚至无法想象。提前感谢您的帮助 这是lambda工作方式的一个众所周知的问题:它被记录在案 您可以通过以下几种方式解决此问题: 使用
functools.partial
而不是lambda
functools.partial
是模块中的一个对象,它将可调用函数和参数绑定在一起。您可以像使用lambda一样使用它:
from functools import partial
for i in range(0, numFloors):
floor = i
btnName = 'floor'+str(floor)+'ViewBtn'
btnLabel = "view Floor " + str(floor)
cmd = partial(self.viewFloor, i)
cmds.button(btnName, label= btnLabel, w=20, h=20, command=cmd)
服从某项职能
这里,嵌套函数def将以与lambda相同的方式捕获值——但是嵌套可以防止您看到的问题
顺便说一句,在这两种策略中,self.showFloor需要额外的参数来容纳按钮总是触发的额外布尔值。这里,我想我会发布我如何解决这个问题,以防它对其他人有帮助。 Partial不是一个可行的选项,因为变量cmd(如示例中所示)仍将使用循环更新,因此每个按钮仍返回最后一层。 在Maya中创建动态生成的UI的问题在于,其UI命令是函数而不是类,这意味着您不能在命令中实际存储任何数据,只能传递它。幸运的是,有人走在我前面,将整个Maya UI命令重写为类。您可以在此处找到该库: 为该库编写的功能代码如下:
for i in range(0, numFloors):
floor = i
BTN= mGui.Button()
BTN.data.[`floor`] = floor
BTN.command = self.viewFloor
def viewFloor(self, defaultArg, **kw):
floor = str(kw[`floor`])
for i in range(0, numFloors):
floor = i
BTN= mGui.Button()
BTN.data.[`floor`] = floor
BTN.command = self.viewFloor
def viewFloor(self, defaultArg, **kw):
floor = str(kw[`floor`])