Python + Maya UI?按钮被遮挡了

1 投票
2 回答
3205 浏览
提问于 2025-04-18 04:06

我不太确定我哪里出错了。我在用Python制作Maya界面方面还是个新手。我的代码有什么问题呢?我希望底部的按钮能占据对话框的整个宽度。我觉得布局是对的,但运行代码时,按钮似乎被某个列挡住了。

'''
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

2 个回答

2

Maya的用户界面系统背后有一套逻辑。一旦你习惯了这些布局和控件的层级关系,它就会以非常可控和可预测的方式运行。

我用过PyQT(PySide)和Maya的用户界面框架,我觉得Maya的界面一点也不笨重。实际上,Maya的用户界面系统比PyQT更简洁、更省事。用Maya的代码可以用更少的行数实现相同的界面布局和功能。当然,QT最大的优点是它可以跨平台和跨软件使用,这一点就足够让人选择它了。

如果你不打算让你的代码在Maya之外使用,那么使用Maya的用户界面的好处是,命令和你的代码会尽可能长时间地得到支持。

以最近的Maya 2017为例。从Maya 2016开始,用户界面框架切换到了PyQT 5和PySide 2。这会导致之前用PyQt4和PySide 1写的代码无法运行。但是,如果你是用Maya的用户界面系统写的代码,它会继续正常工作。当然,把你的PyQT代码修改为兼容新框架可能只需要在编辑器中搜索和替换,但仍然有可能会出错。

在使用Maya的用户界面时,使用columnLayoutrowLayout,你需要注意你创建组件的层级。

rowColumnLayout可能会让人困惑,因为它同时控制行和列的数量。我通常会使用一个主要的columnLayout(垂直排列),当我需要多个控件水平排列时,我会单独为那一行使用rowLayout

setParent是你的好帮手。使用setParent可以把你创建用户界面的“光标/指针”放回到你想要的界面层级下。

在我的第一个示例代码中,我展示了如何用变量存储布局的名称。这样我就可以轻松地在用户界面组件的不同层级之间跳转。

用户界面截图 1

运行我接下来的代码块,看看我们在布局上的灵活性。这对于我在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()

只需稍微修改一下代码,我就可以实现以下效果: 用户界面截图 2

原来的布局仍然在这里,但现在我把它放进了一个更大的rowLayout的列中。

这是生成这个布局的代码。

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()

希望这能改变你对Maya用户界面系统的看法。它仍然有很多优点。

最重要的是,Maya会尽可能在各个版本中继续支持这些命令,并且在Windows、MacOS和Linux上看起来和表现都很相似。

2

天哪,我真讨厌Maya的布局。还是用formLayout吧!(如果不使用QT的话)

看起来rowColumnLayout的宽度是第一列的宽度,尽管它并不是第一个rowColumnLayout的子元素。你可以明确设置宽度:

cmds.setParent(window)
cmds.rowColumnLayout('rlRun', nc=1)

cmds.button('btnCreateQuadSphere', l="Create", w=180, h=30)

考虑到你只有一列,没必要用rowColumnLayout,直接用columnLayout就行了:

cmds.columnLayout('rlRun', width=180)

截图:

在这里输入图片描述

撰写回答