Reputation: 6147
I'm not quite sure where I'm going wrong here. I'm new to the maya scene in terms of python GUI making. What is messed up in my code? I want the bottom button to span the entire width of the dialog. I thought the layout was correct but when you run the code the button seems to be getting stuck behind some column.
'''
John Martini
Quad Sphere 1.0
More info on how to use it can be found at
http://JokerMartini.com
'''
import maya.cmds as cmds
import random
class jmQuadSphere(object):
def __init__(self):
pass
def show(self):
self.GUI()
def GUI(self):
#check to see if our window exists
window = "jmQuadSphere"
if cmds.window(window, exists=True):
cmds.deleteUI(window)
# create our window
window = cmds.window("jmQuadSphere", title = "Quad Sphere", mnb = False, mxb = False, sizeable = False)
cmds.setParent(window)
# Row layout that specifies 3 columns and the width for each column.
cmds.rowColumnLayout('rlOpts', nc=2, cw=[(1,90),(2,90)])
# Each button after the row layout is automatically insterted into the columns numerically
cmds.text( label='Radius:', align='left' )
cmds.floatField('spRadius', minValue=0, maxValue=999999999, value=10, precision=3, step=.01 )
cmds.text( label='Height:', align='left' )
cmds.floatField('spHeight', minValue=0, maxValue=999999999, value=10, precision=3, step=.01 )
cmds.text( label='Width:', align='left' )
cmds.floatField('spWidth', minValue=0, maxValue=999999999, value=10, precision=3, step=.01 )
cmds.text( label='Depth:', align='left' )
cmds.floatField('spDepth', minValue=0, maxValue=999999999, value=10, precision=3, step=.01 )
cmds.text( label='Height Segs:', align='left' )
cmds.intField('spHeightSegs', minValue=0, maxValue=999999999, value=4 )
cmds.text( label='Width Segs:', align='left' )
cmds.intField('spWidthSegs', minValue=0, maxValue=999999999, value=4 )
cmds.text( label='Depth Segs:', align='left' )
cmds.intField('spDepthSegs', minValue=0, maxValue=999999999, value=4 )
cmds.text( label='Roundness:', align='left' )
cmds.floatField('spRoundness', minValue=0, maxValue=100, value=100, precision=2, step=.01 )
cmds.text( label='Flatness:', align='left' )
cmds.floatField('spFlatness', minValue=0, maxValue=100, value=0, precision=2, step=.01 )
cmds.setParent(window)
cmds.rowColumnLayout('rlRun', nc=1)
cmds.button('btnCreateQuadSphere', l="Create", w=180, h=30)
# show window
cmds.showWindow(window)
#execute tool
jmQuadSphere().show()
cmds.scriptEditorInfo(ch=True)
Screenshot:
Upvotes: 1
Views: 3369
Reputation: 61
Maya's UI system is created with a set of logic behind it. It will work well in very controlled and predictable ways once you get used to the rationale behind the hierarchy of the layouts and controls.
I have worked with both PyQT (PySide) and Maya's UI framework, and I don't find Maya's to be clunky at all. In fact, Maya's UI system is more streamlined and fuss-free than PyQT. It takes lesser lines of code to get the same UI layout and functionality. Of course, the biggest advantage of QT is the cross-platform and cross-software independence. This alone is enough reason to pick it up.
If you don't intend for your code to be portable outside of Maya, the benefit of using Maya's UI is that the commands and thus your code will always be supported as far into the future as possible.
Take the recent Maya 2017 for example. From Maya 2016 onwards, the UI framework was switched to PyQT 5 and PySide 2. This will break the code written for PyQt4 and PySide 1. However, if you have written your UI with Maya's UI system, it will continue working fine. Of course, revising your PyQT based code to make the changes required to be compatible with the new framework could be as simple as a search and replace in the editor, but there will still be a chance that you could break something.
For this way of working with Maya's UI with columnLayout
, rowLayout
, you need to keep tabs (pardon the pun) on the level which you are creating your components.
rowColumnLayout
is confusing because of the sheer amount of control over rows and columns all at once. I usually work with a main columnLayout
(vertically going down the UI), and when I need multiple controls laid out horizontally, I will use the rowLayout
just for that row.
setParent
is your friend. Use setParent
to put your UI creation 'cursor/pointer' back under the level of UI hierarchy you want.
In my first example code, I show how I use variables to store the names of layouts. This way I can easily jump between different levels in the UI hierarchy of components.
Run my following block of code and see the flexibility we have with the layout. It is enough for what I need to do with UIs in Maya.
import maya.cmds as mc
def buildUI():
winName = 'myWindow'
winWidth = 200 # set a target width and reference this when you specify width
if mc.window(winName, exists=True):
mc.deleteUI(winName)
mc.window(winName, width=winWidth, title='Test Window')
# i always have keep a reference to the main columnLayout
mainCL = mc.columnLayout()
mc.text(label='text row 1')
# tmpRowWidth controls the width of my columns in the rowLayout
# with reference to winWidth
tmpRowWidth = [winWidth*0.3, winWidth*0.7]
mc.rowLayout(numberOfColumns=2, columnWidth2=tmpRowWidth)
# at this point our UI pointer is under the rowLayout
mc.text(label='row column1', align='center', width=tmpRowWidth[0])
mc.button(label='column 2', width=tmpRowWidth[1])
# we've used up number of children components, if you add 1 more,
# Maya will throw an error
# now to move our pointer back up the hierarchy,
# which is our main columnLayout, mainCL
mc.setParent('..') # also can use mc.setParent(mainCL)
tmpRowWidth = [winWidth*0.5, winWidth*0.5]
mc.rowLayout(numberOfColumns=2, columnWidth2=tmpRowWidth)
mc.text(label='row column1', align='center', width=tmpRowWidth[0])
mc.button(label='column 2', width=tmpRowWidth[1])
mc.setParent('..')
tmpRowWidth = [winWidth*0.7, winWidth*0.3]
mc.rowLayout(numberOfColumns=2, columnWidth2=tmpRowWidth)
mc.text(label='row column1', align='center', width=tmpRowWidth[0])
mc.button(label='column 2', width=tmpRowWidth[1])
mc.setParent('..')
mc.text(label='text row 3')
tmpWidth = [winWidth*0.3, winWidth*0.5, winWidth*0.2]
mc.textFieldButtonGrp(label='txt field', w=winWidth, columnWidth3=tmpWidth, buttonLabel='okay')
mc.button('full width button', width=winWidth)
mc.showWindow(winName)
mc.window(winName, e=True, width=winWidth, height=1)
return
buildUI()
With a little bit of change in code, I can achieve the following:
The original layout is still in there, but now I've put it into a column of a larger rowLayout
.
Here is the code that generated this.
import maya.cmds as mc
def buildUI():
winName = 'myWindow'
winWidth = 400 # set a target width and reference this when you specify width
if mc.window(winName, exists=True):
mc.deleteUI(winName)
mc.window(winName, width=winWidth, title='Test Window')
# i always have keep a reference to the main columnLayout
mainCL = mc.columnLayout()
mainRLWidth = [winWidth*0.6, winWidth*0.4]
mainRL = mc.rowLayout(w=winWidth, numberOfColumns=2, columnWidth2=mainRLWidth, rowAttach=(2, 'top', 0))
mc.columnLayout(w=mainRLWidth[0]) # create a columnLayout under the first row of mainRL
mc.text(label='mainRL column 1', font='boldLabelFont')
mc.text(label='')
mc.text(label='text row 1')
# tmpRowWidth controls the width of my columns in the rowLayout
# with reference to winWidth
tmpRowWidth = [mainRLWidth[0]*0.3, mainRLWidth[0]*0.7]
mc.rowLayout(numberOfColumns=2, columnWidth2=tmpRowWidth)
# at this point our UI pointer is under the rowLayout
mc.text(label='row column1', align='center', width=tmpRowWidth[0])
mc.button(label='column 2', width=tmpRowWidth[1])
# we've used up number of children components, if you add 1 more,
# Maya will throw an error
# now to move our pointer back up the hierarchy,
# which is our main rowLayout, mainRL
mc.setParent('..') # also can use mc.setParent(mainRL)
tmpRowWidth = [mainRLWidth[0]*0.5, mainRLWidth[0]*0.5]
mc.rowLayout(numberOfColumns=2, columnWidth2=tmpRowWidth)
mc.text(label='row column1', align='center', width=tmpRowWidth[0])
mc.button(label='column 2', width=tmpRowWidth[1])
mc.setParent('..')
tmpRowWidth = [mainRLWidth[0]*0.7, mainRLWidth[0]*0.3]
mc.rowLayout(numberOfColumns=2, columnWidth2=tmpRowWidth)
mc.text(label='row column1', align='center', width=tmpRowWidth[0])
mc.button(label='column 2', width=tmpRowWidth[1])
mc.setParent('..')
mc.text(label='text row 3')
tmpWidth = [mainRLWidth[0]*0.3, mainRLWidth[0]*0.5, mainRLWidth[0]*0.2]
mc.textFieldButtonGrp(label='txt field', w=mainRLWidth[0], columnWidth3=tmpWidth, buttonLabel='okay')
mc.button('full row width button', width=mainRLWidth[0])
mc.setParent('..') # this will exit the rowLayout back to the mainRL, same as mc.setParent(mainRL)
mc.columnLayout(width=mainRLWidth[1]) # start another vertical layout
mc.text(label='mainRL column 2', font='boldLabelFont')
mc.text(label='')
mc.text(label='text row 1')
mc.button(label='button', width=mainRLWidth[1]*0.95, height=70)
mc.setParent(mainCL) # set UI pointer back under the main columnLayout
mc.text(label='')
mc.button(label='full window width button', width=winWidth, height=40)
mc.showWindow(winName)
mc.window(winName, e=True, width=winWidth, height=1)
return
buildUI()
I hope this has changed your opinon of Maya's set of UI system. It still has a lot going for it.
Most important of all, Maya will keep supporting these commands across its versions as much as possible, and it will still look and behave similarly across Windows, MacOS and Linux.
Upvotes: 2
Reputation: 23251
Gawd I hate Maya's layouts. formLayout
all the way! (If not QT)
It looks like the rowColumnLayout
is the width of the first column, even though it's not a child of the first rowColumnLayout
. You can explicitly set the width:
cmds.setParent(window)
cmds.rowColumnLayout('rlRun', nc=1)
cmds.button('btnCreateQuadSphere', l="Create", w=180, h=30)
Considering you only have one column, there's no reason to use rowColumnLayout
when you can just use columnLayout
:
cmds.columnLayout('rlRun', width=180)
Screenshot:
Upvotes: 2