Maya Python - Using data from UI

2019-01-12 04:52发布

问题:

I am working on a scripting program and struggling a bit with the UI. I've made a couple of UIs, all of which seem to work fine individually, but I don't know how to use the data inputted in a UI to another function. I'm trying to get the Gun Type (selected by the user in Bullet_Spray_Generator) to then affect which of the UIs is then called. Each Gun Type requires a different set of values for the sliders, so I made a different UI for each. I think I need to pass the data selected from the BSG into an if function in order to call the correct (second) UI, but running it just always jumps to the else function and closes the window. Here's my code so far:

import maya.cmds as cmds
from functools import partial


if (cmds.window("Bullet_Spray_Generator", exists = True)): 
    cmds.deleteUI("Bullet_Spray_Generator")
if (cmds.window("BSG2", exists = True)): 
    cmds.deleteUI("BSG2")

cmds.select(all=True)
cmds.delete()



def goShoot(numOfShots, distToTarget, *pArgs): 
    print "Begin"
    cmds.deleteUI("BSG2")
    createWall()

def cancelShoot(*pArgs):
    print "cancel"
    cmds.deleteUI("Bullet_Spray_Generator")


def createWall():
    cmds.select(all=True)
    cmds.delete()
    wall = cmds.polyCube(h=10, w=15, d=1, name='wall')
    cmds.move(0,5,0, 'wall')


def createGunUI(gunType, *pArgs):
    if (GunSelectCtrl == 'Pistol'):
        createPistolUI()
    elif (GunSelectCtrl == 'Shotgun'):
        createShotgunUI()
    elif (GunSelectCtrl == 'SMG'):
        createSMGUI()
    elif (GunSelectCtrl == 'Sniper Rifle'):
        createSniperUI()
    elif (GunSelectCtrl == 'RPG'):
        createRPGUI()
    else:
        print "Something went wrong"
        cancelShoot()



def createPistolUI():
    cmds.window("Pistol")
    cmds.columnLayout(adjustableColumn=True)

    cmds.deleteUI("Bullet_Spray_Generator")

    NumBulletsCtrl = cmds.intSliderGrp(label='Number of Shots',
    minValue=1, maxValue=9, value=4, field=True)

    DistCtrl = cmds.intSliderGrp(label='Distance to Target (metres)', 
    minValue=1, maxValue=50, value=25, field=True)

    cmds.button(label = "Fire", command = lambda *args: goShoot(cmds.intSliderGrp(NumBulletsCtrl, 
    query=True, value=True), cmds.intSliderGrp(DistCtrl, query=True, value=True), ))

    cmds.button(label = "Cancel", command = cancelShoot)

    cmds.showWindow("Pistol")

def createShotgunUI():
    cmds.window("Shotgun")
    cmds.columnLayout(adjustableColumn=True)

    cmds.deleteUI("Bullet_Spray_Generator")

    NumBulletsCtrl = cmds.intSliderGrp(label='Number of Shots',
    minValue=1, maxValue=4, value=2, field=True)

    DistCtrl = cmds.intSliderGrp(label='Distance to Target (metres)', 
    minValue=1, maxValue=50, value=25, field=True)

    cmds.button(label = "Fire", command = lambda *args: goShoot(cmds.intSliderGrp(NumBulletsCtrl, 
    query=True, value=True), cmds.intSliderGrp(DistCtrl, query=True, value=True), ))

    cmds.button(label = "Cancel", command = cancelShoot)

    cmds.showWindow("Shotgun")

def createSMGUI():
    cmds.window("SMG")
    cmds.columnLayout(adjustableColumn=True)

    cmds.deleteUI("Bullet_Spray_Generator")

    NumBulletsCtrl = cmds.intSliderGrp(label='Number of Shots',
    minValue=1, maxValue=20, value=4, field=True)

    DistCtrl = cmds.intSliderGrp(label='Distance to Target (metres)', 
    minValue=1, maxValue=50, value=25, field=True)

    cmds.button(label = "Fire", command = lambda *args: goShoot(cmds.intSliderGrp(NumBulletsCtrl, 
    query=True, value=True), cmds.intSliderGrp(DistCtrl, query=True, value=True), ))

    cmds.button(label = "Cancel", command = cancelShoot)

    cmds.showWindow("SMG")

def createSniperUI():
    cmds.window("Sniper")
    cmds.columnLayout(adjustableColumn=True)

    cmds.deleteUI("Bullet_Spray_Generator")

    NumBulletsCtrl = cmds.intSliderGrp(label='Number of Shots',
    minValue=1, maxValue=2, value=2, field=True)

    DistCtrl = cmds.intSliderGrp(label='Distance to Target (metres)', 
    minValue=1, maxValue=50, value=25, field=True)

    cmds.button(label = "Fire", command = lambda *args: goShoot(cmds.intSliderGrp(NumBulletsCtrl, 
    query=True, value=True), cmds.intSliderGrp(DistCtrl, query=True, value=True), ))

    cmds.button(label = "Cancel", command = cancelShoot)

    cmds.showWindow("Sniper")

def createRPGUI():
    cmds.window("RPG")
    cmds.columnLayout(adjustableColumn=True)

    cmds.deleteUI("Bullet_Spray_Generator")

    NumBulletsCtrl = cmds.intSliderGrp(label='Number of Shots',
    minValue=1, maxValue=1, value=1, field=True)

    DistCtrl = cmds.intSliderGrp(label='Distance to Target (metres)', 
    minValue=1, maxValue=50, value=25, field=True)

    cmds.button(label = "Fire", command = lambda *args: goShoot(cmds.intSliderGrp(NumBulletsCtrl, 
    query=True, value=True), cmds.intSliderGrp(DistCtrl, query=True, value=True), ))

    cmds.button(label = "Cancel", command = cancelShoot)

    cmds.showWindow("RPG")


def printNewMenuItem(item):
    print item
    return item


def createUI(): 
    cmds.window("Bullet_Spray_Generator")
    cmds.columnLayout(adjustableColumn=True)

    GunSelectCtrl = cmds.optionMenu(label='Gun', changeCommand=printNewMenuItem)
    cmds.menuItem(label='Pistol')
    cmds.menuItem(label='Shotgun')
    cmds.menuItem(label='SMG')
    cmds.menuItem(label='Sniper Rifle')
    cmds.menuItem(label='RPG')

    cmds.button(label = "Continue", command = partial(createGunUI, GunSelectCtrl))

    cmds.button(label = "Cancel", command = cancelShoot)

    cmds.showWindow("Bullet_Spray_Generator")

createUI()

Any help would be greatly appreciated, thanks very much.

回答1:

You should use Dictionaries :

myDic = {}

myDic["anyString"] = "Value, String, Tuples,...etc"

print myDic

The good point of using dic is that you won't have to worry about nested variables.

To demonstrate the power of dictionnaries, I also add a function createWeaponUI().

If you hit "Continue" with Shotgun selected, it will create a pistol/shotgun UI with createWeaponUI(). You just have to add storedDataDic["weqponYouWant_preset"] for each weapons at the top to generate whatever ui you want. It is easier to read than 50 UI copy/pasted and use 50 if/elif to tell what weapon ui you should use.

Here is your modified script using dic:

import maya.cmds as cmds
from functools import partial

storedDataDic = {}
storedDataDic["weapon"] = ["Pistol", "Shotgun", "SMG", "Sniper Rifle", "RPG"]
storedDataDic["weaponSelected"] = storedDataDic["weapon"][0]
storedDataDic["Shotgun_preset"] = [(1,4,2), (1,50,25)]
storedDataDic["Pistol_preset"] = [(1,18,2), (1,25,10)]

if (cmds.window("Bullet_Spray_Generator", exists = True)): 
    cmds.deleteUI("Bullet_Spray_Generator")
if (cmds.window("BSG2", exists = True)): 
    cmds.deleteUI("BSG2")

cmds.select(all=True)
cmds.delete()



def goShoot(numOfShots, distToTarget, *pArgs): 
    print "Begin"
    cmds.deleteUI("BSG2")
    createWall()

def cancelShoot(*pArgs):
    print "cancel"
    cmds.deleteUI("Bullet_Spray_Generator")


def createWall():
    cmds.select(all=True)
    cmds.delete()
    wall = cmds.polyCube(h=10, w=15, d=1, name='wall')
    cmds.move(0,5,0, 'wall')


def createGunUI(gunType, *pArgs):
    if (gunType == 'Pistol'):
        createWeaponUI()
    elif (gunType == 'Shotgun'):
        createWeaponUI()
    elif (gunType == 'SMG'):
        createSMGUI()
    elif (gunType == 'Sniper Rifle'):
        createSniperUI()
    elif (gunType == 'RPG'):
        createRPGUI()
    else:
        print "Something went wrong"
        cancelShoot()



def createPistolUI():
    cmds.window("Pistol")
    cmds.columnLayout(adjustableColumn=True)

    cmds.deleteUI("Bullet_Spray_Generator")

    NumBulletsCtrl = cmds.intSliderGrp(label='Number of Shots',
    minValue=1, maxValue=9, value=4, field=True)

    DistCtrl = cmds.intSliderGrp(label='Distance to Target (metres)', 
    minValue=1, maxValue=50, value=25, field=True)

    cmds.button(label = "Fire", command = lambda *args: goShoot(cmds.intSliderGrp(NumBulletsCtrl, 
    query=True, value=True), cmds.intSliderGrp(DistCtrl, query=True, value=True), ))

    cmds.button(label = "Cancel", command = cancelShoot)

    cmds.showWindow("Pistol")

def createShotgunUI():
    cmds.window("Shotgun")
    cmds.columnLayout(adjustableColumn=True)

    cmds.deleteUI("Bullet_Spray_Generator")

    NumBulletsCtrl = cmds.intSliderGrp(label='Number of Shots',
    minValue=1, maxValue=4, value=2, field=True)

    DistCtrl = cmds.intSliderGrp(label='Distance to Target (metres)', 
    minValue=1, maxValue=50, value=25, field=True)

    cmds.button(label = "Fire", command = lambda *args: goShoot(cmds.intSliderGrp(NumBulletsCtrl, 
    query=True, value=True), cmds.intSliderGrp(DistCtrl, query=True, value=True), ))

    cmds.button(label = "Cancel", command = cancelShoot)

    cmds.showWindow("Shotgun")

def createSMGUI():
    cmds.window("SMG")
    cmds.columnLayout(adjustableColumn=True)

    cmds.deleteUI("Bullet_Spray_Generator")

    NumBulletsCtrl = cmds.intSliderGrp(label='Number of Shots',
    minValue=1, maxValue=20, value=4, field=True)

    DistCtrl = cmds.intSliderGrp(label='Distance to Target (metres)', 
    minValue=1, maxValue=50, value=25, field=True)

    cmds.button(label = "Fire", command = lambda *args: goShoot(cmds.intSliderGrp(NumBulletsCtrl, 
    query=True, value=True), cmds.intSliderGrp(DistCtrl, query=True, value=True), ))

    cmds.button(label = "Cancel", command = cancelShoot)

    cmds.showWindow("SMG")

def createSniperUI():
    cmds.window("Sniper")
    cmds.columnLayout(adjustableColumn=True)

    cmds.deleteUI("Bullet_Spray_Generator")

    NumBulletsCtrl = cmds.intSliderGrp(label='Number of Shots',
    minValue=1, maxValue=2, value=2, field=True)

    DistCtrl = cmds.intSliderGrp(label='Distance to Target (metres)', 
    minValue=1, maxValue=50, value=25, field=True)

    cmds.button(label = "Fire", command = lambda *args: goShoot(cmds.intSliderGrp(NumBulletsCtrl, 
    query=True, value=True), cmds.intSliderGrp(DistCtrl, query=True, value=True), ))

    cmds.button(label = "Cancel", command = cancelShoot)

    cmds.showWindow("Sniper")

def createRPGUI():
    cmds.window("RPG")
    cmds.columnLayout(adjustableColumn=True)

    cmds.deleteUI("Bullet_Spray_Generator")

    NumBulletsCtrl = cmds.intSliderGrp(label='Number of Shots',
    minValue=1, maxValue=1, value=1, field=True)

    DistCtrl = cmds.intSliderGrp(label='Distance to Target (metres)', 
    minValue=1, maxValue=50, value=25, field=True)

    cmds.button(label = "Fire", command = lambda *args: goShoot(cmds.intSliderGrp(NumBulletsCtrl, 
    query=True, value=True), cmds.intSliderGrp(DistCtrl, query=True, value=True), ))

    cmds.button(label = "Cancel", command = cancelShoot)

    cmds.showWindow("RPG")


def printNewMenuItem(item):
    print item
    storedDataDic["weaponSelected"] = item
    return storedDataDic["weaponSelected"]

def ui_refreshSelWeapon(fun, *args):
    createGunUI(storedDataDic["weaponSelected"])

def createUI(): 
    cmds.window("Bullet_Spray_Generator")
    cmds.columnLayout(adjustableColumn=True)

    GunSelectCtrl = cmds.optionMenu(label='Gun', changeCommand=printNewMenuItem)
    for i in storedDataDic["weapon"]:
        cmds.menuItem(label=i)

    cmds.button(label = "Continue", command = ui_refreshSelWeapon)

    cmds.button(label = "Cancel", command = cancelShoot)

    cmds.showWindow("Bullet_Spray_Generator")

createUI()



weapon_uiDic = {}

def createWeaponUI():

    weaponName = storedDataDic["weaponSelected"]

    if cmds.window(weaponName, exists=True):
        cmds.deleteUI(weaponName)
    cmds.window(weaponName)
    cmds.columnLayout(adjustableColumn=True)

    cmds.deleteUI("Bullet_Spray_Generator")



    nbP= storedDataDic[weaponName + "_preset"][0]
    dcP = storedDataDic[weaponName + "_preset"][1]

    weapon_uiDic["NumBulletsCtrl"] = cmds.intSliderGrp(label='Number of Shots',
    minValue=nbP[0], maxValue=nbP[1], value=nbP[2], field=True)

    weapon_uiDic["DistCtrl"] = cmds.intSliderGrp(label='Distance to Target (metres)', 
    minValue=dcP[0], maxValue=dcP[1], value=dcP[2], field=True)

    weapon_uiDic["fireButton"] = cmds.button(label = "Fire", 
                                            command = lambda *args: goShoot(cmds.intSliderGrp(weapon_uiDic["NumBulletsCtrl"], 
    query=True, value=True), cmds.intSliderGrp(weapon_uiDic["DistCtrl"], query=True, value=True)))

    cmds.button(label = "Cancel", command = cancelShoot)

    cmds.showWindow(weaponName)

---EDIT---

I had pistol preset to make it more clear



回答2:

The easiest way to pass complex information around inside a GUI in Maya is to wrap the whole UI in python class. The class can 'remember' all of your fields, sliders, etc so that you can easily collect information from one or more GUI items and act on them without too much extra work.

class PistoUI(object):

    def __init__(self):
        self.window =  cmds.window("Pistol")
        cmds.columnLayout(adjustableColumn=True)
        self.bullet_count = cmds.intSliderGrp(label='Number of Shots', minValue=1, maxValue=9, value=4, field=True)
        self.distance = cmds.intSliderGrp(label='Distance to Target (metres)',  minValue=1, maxValue=50, value=25, field=True)
        cmds.button(label = "Fire", command = self.fire)
        cmds.button(label = "Cancel", command = self.cancel)
        cmds.showWindow(self.window)

    def fire(self, _ignore):
        bullets  =  cmds.intSliderGrp(self.bullet_count, q=True, v=True)
        distance = cmds.intSliderGrp(self.distance, q=True, v=True).
        goShoot(bullets, distance)

    def cancel(self, _ignore):
        cmds.deleteUI(self.window)

As you can see above, the fire function gets the correct fields from the active window and collects their values to pass to the goShoot function without any extra work in the layout step to pass the values directly to a function. This is much simpler and more elegant than leaving all the pieces lying around in the open. It's also more self-contained - you can create multiple windows side-by-side in that scheme without worrying about creating and deleting them by name.

Even better, the clases are really good for separating out differences in logic from difference in data, so you can resuse the repetitive code with ease:

class WeaponUI(object):
    LABEL = 'weapon_name'  #default name
    SHOTS = (1, 9, 4)   # default shots
    RANGE = (1, 50, 25)  # default range

    def __init__(self):
        self.window =  cmds.window(title = self.LABEL)
        cmds.columnLayout(adjustableColumn=True)
        self.bullet_count = cmds.intSliderGrp(label='Number of Shots', minValue=self.SHOTS[0],
                                                    maxValue=self.SHOTS[1],
                                                    value=self.SHOTS[2], field=True)
        self.distance = cmds.intSliderGrp(label='Distance to Target (metres)',  
                                                    minValue=self.RANGE[0], 
                                                    maxValue=self.RANGE[1], 
                                                    value=self.RANGE[2], field=True)
        cmds.button(label = "Fire", command = self.fire)
        cmds.button(label = "Cancel", command = self.cancel)
        cmds.showWindow(self.window)


    def fire(self, _ignore):
        bullets  =  cmds.intSliderGrp(self.bullet_count, q=True, v=True)
        distance = cmds.intSliderGrp(self.distance, q=True, v=True).
        print "firing", self.LABEL
        goShoot(bullets, target)

    def cancel(self, _ignore):
        cmds.deleteUI(self.window)

class PistolUI(WeaponUI):
    LABEL = 'pistol'  
    SHOTS = (1, 9, 4)   
    RANGE = (1, 50, 25) 

class ShotgunUI(WeaponUI):
    LABEL = 'shotgun'  
    SHOTS = (1, 4, 2)  
    RANGE = (1, 50, 25) 

class SniperUI(WeaponUI):
    LABEL = 'sniper'  
    SHOTS = (1, 4, 2)  
    RANGE = (1, 50, 25) 

... and so on

More about maya GUI connections here and here



回答3:

The reason why it fails is GunSelectCtrl is an UI control which is the option menu created in createUI method. It is not a string. In createGunUI method, you treat GunSelectCtrl as a string, if statement will of course fail.

You need to use command cmds.optionMenu(GunSelectCtrl, value=True, q=True) to retrieve the string gun type.

Besides, there is an error when I run the script:

global name 'GunSelectCtrl' is not defined # 

You need to define it as a global variable and declare it where it is used: methods createUI and createGunUI.

The modified code is below:

import maya.cmds as cmds
from functools import partial


if (cmds.window("Bullet_Spray_Generator", exists = True)): 
    cmds.deleteUI("Bullet_Spray_Generator")
if (cmds.window("BSG2", exists = True)): 
    cmds.deleteUI("BSG2")

cmds.select(all=True)
cmds.delete()

GunSelectCtrl = ""

def goShoot(numOfShots, distToTarget, *pArgs): 
    print "Begin"
    cmds.deleteUI("BSG2")
    createWall()

def cancelShoot(*pArgs):
    print "cancel"
    cmds.deleteUI("Bullet_Spray_Generator")


def createWall():
    cmds.select(all=True)
    cmds.delete()
    wall = cmds.polyCube(h=10, w=15, d=1, name='wall')
    cmds.move(0,5,0, 'wall')


def createGunUI(gunType, *pArgs):
    global GunSelectCtrl
    gunType = cmds.optionMenu(GunSelectCtrl, value=True, q=True)

    if (gunType == 'Pistol'):
        createPistolUI()
    elif (gunType == 'Shotgun'):
        createShotgunUI()
    elif (gunType == 'SMG'):
        createSMGUI()
    elif (gunType == 'Sniper Rifle'):
        createSniperUI()
    elif (gunType == 'RPG'):
        createRPGUI()
    else:
        print "Something went wrong"
        cancelShoot()



def createPistolUI():
    cmds.window("Pistol")
    cmds.columnLayout(adjustableColumn=True)

    cmds.deleteUI("Bullet_Spray_Generator")

    NumBulletsCtrl = cmds.intSliderGrp(label='Number of Shots',
    minValue=1, maxValue=9, value=4, field=True)

    DistCtrl = cmds.intSliderGrp(label='Distance to Target (metres)', 
    minValue=1, maxValue=50, value=25, field=True)

    cmds.button(label = "Fire", command = lambda *args: goShoot(cmds.intSliderGrp(NumBulletsCtrl, 
    query=True, value=True), cmds.intSliderGrp(DistCtrl, query=True, value=True), ))

    cmds.button(label = "Cancel", command = cancelShoot)

    cmds.showWindow("Pistol")

def createShotgunUI():
    cmds.window("Shotgun")
    cmds.columnLayout(adjustableColumn=True)

    cmds.deleteUI("Bullet_Spray_Generator")

    NumBulletsCtrl = cmds.intSliderGrp(label='Number of Shots',
    minValue=1, maxValue=4, value=2, field=True)

    DistCtrl = cmds.intSliderGrp(label='Distance to Target (metres)', 
    minValue=1, maxValue=50, value=25, field=True)

    cmds.button(label = "Fire", command = lambda *args: goShoot(cmds.intSliderGrp(NumBulletsCtrl, 
    query=True, value=True), cmds.intSliderGrp(DistCtrl, query=True, value=True), ))

    cmds.button(label = "Cancel", command = cancelShoot)

    cmds.showWindow("Shotgun")

def createSMGUI():
    cmds.window("SMG")
    cmds.columnLayout(adjustableColumn=True)

    cmds.deleteUI("Bullet_Spray_Generator")

    NumBulletsCtrl = cmds.intSliderGrp(label='Number of Shots',
    minValue=1, maxValue=20, value=4, field=True)

    DistCtrl = cmds.intSliderGrp(label='Distance to Target (metres)', 
    minValue=1, maxValue=50, value=25, field=True)

    cmds.button(label = "Fire", command = lambda *args: goShoot(cmds.intSliderGrp(NumBulletsCtrl, 
    query=True, value=True), cmds.intSliderGrp(DistCtrl, query=True, value=True), ))

    cmds.button(label = "Cancel", command = cancelShoot)

    cmds.showWindow("SMG")

def createSniperUI():
    cmds.window("Sniper")
    cmds.columnLayout(adjustableColumn=True)

    cmds.deleteUI("Bullet_Spray_Generator")

    NumBulletsCtrl = cmds.intSliderGrp(label='Number of Shots',
    minValue=1, maxValue=2, value=2, field=True)

    DistCtrl = cmds.intSliderGrp(label='Distance to Target (metres)', 
    minValue=1, maxValue=50, value=25, field=True)

    cmds.button(label = "Fire", command = lambda *args: goShoot(cmds.intSliderGrp(NumBulletsCtrl, 
    query=True, value=True), cmds.intSliderGrp(DistCtrl, query=True, value=True), ))

    cmds.button(label = "Cancel", command = cancelShoot)

    cmds.showWindow("Sniper")

def createRPGUI():
    cmds.window("RPG")
    cmds.columnLayout(adjustableColumn=True)

    cmds.deleteUI("Bullet_Spray_Generator")

    NumBulletsCtrl = cmds.intSliderGrp(label='Number of Shots',
    minValue=1, maxValue=1, value=1, field=True)

    DistCtrl = cmds.intSliderGrp(label='Distance to Target (metres)', 
    minValue=1, maxValue=50, value=25, field=True)

    cmds.button(label = "Fire", command = lambda *args: goShoot(cmds.intSliderGrp(NumBulletsCtrl, 
    query=True, value=True), cmds.intSliderGrp(DistCtrl, query=True, value=True), ))

    cmds.button(label = "Cancel", command = cancelShoot)

    cmds.showWindow("RPG")


def printNewMenuItem(item):
    print item
    return item


def createUI():
    global GunSelectCtrl
    cmds.window("Bullet_Spray_Generator")
    cmds.columnLayout(adjustableColumn=True)

    GunSelectCtrl = cmds.optionMenu(label='Gun', changeCommand=printNewMenuItem)
    cmds.menuItem(label='Pistol')
    cmds.menuItem(label='Shotgun')
    cmds.menuItem(label='SMG')
    cmds.menuItem(label='Sniper Rifle')
    cmds.menuItem(label='RPG')

    cmds.button(label = "Continue", command = partial(createGunUI, GunSelectCtrl))

    cmds.button(label = "Cancel", command = cancelShoot)

    cmds.showWindow("Bullet_Spray_Generator")

createUI()