Search code examples
pythonloopsuser-interfacemayaautodesk

Maya/Python: Creating Unique Commands in Loop-Generated UI


In Autodesk Maya I'm dynamically creating UI based on the number of floors a user wants to make (the variable numFloors is fetched from an intField). For each floor, I want to make a button that changes the height of the camera to look at the floor (this is for buildings). The problem I have is that I can't have my viewFloor() function know which button was pressed in order to activate it. Each time, the button passes the most recent floor rather than the specific floor.

I know why this occurs, the command is not dynamically stored when a button is being created so when a button is clicked, the command uses the most recent instance of the variable, which should be the last floor which is equal to the variable numFloors.

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)

So when numFloors = 4, viewFloor will always have 4 passed to it regardless of which floor button was pressed. Like I said, I'm aware of why this happens, this code snippet was simply my best shot at creating a snippet of code that would communicate what I'm trying to do. Unfortunately, I have no idea how to actually accomplish this.

Some ideas I have are:

Some complicated setattr and getattr setup (but I have no idea how that would work)

or a scriptJob that detects when the button is pressed and passes that specific button's name to the viewFloor function (I could then just pull the digits from the string to get the floor). However, I cannot find any indication of the event or condition that occurs when a button is pressed in the Maya Python documentation. Because of this, I can't create the scriptJob.

If anyone could point me in the right direction (such as the scriptJob flags I might need or an example of a setattr getattr setup) or any other solution I am too uneducated to even conceive it would be very appreciated. Thanks in advance for any assistance!


Solution

  • OP here, thought I would post how I solved the problem in case it helps anyone else. Partial wasn't a viable option because the variable cmd (as found in the example) still would be updated with the loop and therefore each button still returned the last floor. The issue with creating dynamically generated UI in Maya is that its UI commands are functions rather than classes, meaning you can't actually store any data in a command only pass it. Fortunately, someone has gone in ahead of me and rewritten the entirety of Maya's UI commands as classes. You can find that library here: mGui

    The functional code when written for this library is as follows:

    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`])