-
Notifications
You must be signed in to change notification settings - Fork 23
Getting started
Installation is simple: just make sure that the mGui folder (the root one containing __init__.py
, bindings.py
and so on) is in your python path.
If you want to avoid loose files you can zip the root mGui folder and add that zip to your path instead; that will work the same way. If you downloaded a zipped copy of the repo from CreativeCrash, just put that zip into a folder on your Maya python path.
The most common use case is to import everything in mGui.gui. Depending on your personal style you can write
from mGui.gui import *
with Window('root') as w:
with ColumnLayout('col'):
Text('txt', label = 'Example')
w.show()
or
import mGui.gui as gui
with gui.Window('root') as w:
with gui.ColumnLayout('form'):
gui.Text('txt', label = 'Example')
w.show()
These are interchangeable. mGui.gui
is designed to be safe for star imports.
All of the base mGui classes correspond to commands and widgets in maya.cmds. The only difference in naming is that the mGui versions (being classes) as capitalized. Thus:
cmds.button = Button
cmds.menu = Menu
cmds.columnLayout = ColumnLayout
and so on. All of the flags from the maya.cmds version are supported as well. The version here on github uses only the long names of the flags (ie, Button('b', width=100)
rather than Button('b', w=100)
.
If you'd rather use short flag names, you can regenerate your local copy of mGui.core.controls and mGui.core.layouts using the functions generate_controls
and generate_layouts
functions in mGui.helpers. More discussion here
There are two key differences in usage.
This is mostly a semantic issue, but mGui.gui.Button
is a class while cmds.button
is a function. Since the gui widgets get created when the class is instantiated the written code will be almost the same. The real benefits of the class come when you need to do more complex setup, since you can get and set class properties far easily than you can query or edit command objects:
b = Button('go')
b.label = 'some very long string'
b.width = len(b.label) * 10
b.backgroundColor = (1,1,0)
as opposed to
b = cmds.button('go')
cmds.button(b, e=True, label = 'some very long string')
cmds.button(b, e=True, width = len(cmds.button, b, q=True, label=True) * 10)
cmds.button(b, e=True, backgroundColor = (1,1,0))
mGui layout objects are python context managers, which means they support the with
statement. This allows you to see the scope of your layouts clearly:
with Window('w', title = 'example') as w:
with ColumnLayout('main'):
Text(None, label = 'Header text', align = 'center')
with ScrollLayout('scroll'):
with ColumnLayout('subscroll')
Button(label = 'inside a scroll layout')
Button(label = 'inside a scroll layout')
Button(label = 'inside a scroll layout')
with RowLayout('bottom', numberOfChildren=2):
Button(label = 'cancel')
Button(label = 'activate')
In this example the window has 3 immediate children - a Text
, a ScrollLayout
and a RowLayout
. The ScrollLayout
and the RowLayout
have their own children. The context manager makes it obvious who belongs to whom.
Managing a gui is usually kind of tedious. In vanilla Maya gui code, you frequently need to store a lot of gui widgets in variables, since that's the only way to query or edit their properties.
mGui allows you to access gui widgets using a property-like syntax. Since most gui is arranged in some kind of tree (a window contains a layout, the layout contains widgets or other layouts, and so on) this allows you to get at your gui elements without a complex system of variables to track things.
mGui assigns these labels based on local variables you declare as you lay out your gui. These local variables are "captured" by the various layout context managers and become the names of the objects. It's easier to see than to explain:
with Window(title = 'main window') as my_window: # create a window, 'my_window'
with HeaderForm() as main: # a HeaderForm has two children
with VerticalForm() as header:
Text("This is an example")
more_button = Button("Click for more details")
with FooterForm() as body: # a FooterForm also expects two children
content_list= TextScrollList() # a list to hold some data
delete_btn = Button("delete") # a button to manipulate stuff
# add a handler to the 'click for details' button, using the dotted property access
my_window.main.header.more_button.command += some_function
# add some items to the list
my_window.main.body.content_list.items = ['some stuff', 'some more stuff']
# change the label of the delete button
my_window.main.body.delete_btn.label = "Remove"
As you can see here the local variables are captured by the layouts and turned into property names. These property names are not the same as the underlying Maya widget names -- but that's OK. You only interact with the widgets through the mGui objects, which are grouped for you automatically. This is a much easier set of data to manage than many independent individual variables. For items you don't care about (such as that Text()
item, which you won't be changing again`) you don't need to store a variable if you don't want it.
It is worth pointing out that you want to avoid name clashes between your gui widgets and the pre-existing properties on the layouts! Don't name use local variables to name a control 'backgroundColor', for example, or you will get the backgroundColor property of the owning layout instead of the child control.