There is a way in Maya to collect several commands in something called a procedure. There are local procs
and global procs. If you want to use the proc outside the script you have to make it global. When we create
a button and we want that button to call the procedure we have to make it global because the window is
outside the script. (in Maya, but outside the code...) Let's define a proc.

global proc ma_createPrinitives(){

The syntax: "global proc" tells Maya that we want to define the procedure. "ma_createPrimitives" is the name
of the proc that we have to use when we want to call it later. The brackets can include arguements (which we
will go through next.) Now you can see that we have three commands between the curly braces and that's
basicly it for this proc. If you highlight the code above, copy it into Maya and run it you see that nothing
happens. This is because we just store the info in Maya. If we want the chunk of code to be executed we have
to call the proc by writing ma_createPrimitives. Nothing more, nothing less. If you use it in a longer code you
have to terinate the line with ";" of course.

Now I'll go through an example with an argument:

global proc ma_print (string $name){
print ("Hi, my name is " + $name);

Here you can see that the argument is a string. You can have several arguments, you just have to separate
them with a comma. We'll use two arguments in the next example. When we use an argument like this we
tell Maya that we don't have a defined name right now so we depend on user interference. The user/ or
scripter have to tell Maya whitch name to print. When we call the proc it looks like this:

ma_print Martin;

this will print "Hi, my name is Martin". If we write ma_print Robert it will print "Hi, my name is Robert". Now we'll
include an int called $age.

global proc ma_print (string $name, int $age){
print ("Hi, my name is " + $name + ". I'm " + $age + " years young");

So if I write ma_print Martin 24 it will print "Hi, my name is Martin.I'm 24 years young". Just as a final example
I'll create a proc that I'm actually going to use with a button. I'll start by creating the window:

window -t "test" ma_labelWin;
textField -tx "insert label here" -w 150 ma_labelText;
button -l "click me to change label" ma_labelButton;
showWindow ma_labelWin;

This will make a window that looks like this:

We can change the text here, but when we click the button nothing happens. We want the button to change
the label on itself to whatever is in the textField. The proc would look like this:

global proc ma_changeLabel(){
string $ma_getLabel = `textField -q -tx ma_labelText`;
button -e -l $ma_getLabel ma_labelButton;

You can see that I get the input from the textField and cast it into the string $ma_getLabel by querying -tx.
Then I put the button in edit mode to edit the label for the ma_labelButton. The label will get the new value
$ma_getLabel. The final thing we have to do now is to "attach" the proc to the button. If you check the
helpfiles you can see that the button has a "command-flag". What we do now is put the proc as a value to
that flag. Also I included an if statement that checks if the window exists. You know the error you get when
you try to open a window that already exists, this will prevent this.

if (`window -ex ma_labelWin` == 1){
deleteUI ma_labelWin;

window -t "test" ma_labelWin;
textField -tx "insert label here" -w 150 ma_labelText;
button -l "click me to change label" -c ma_changeLabel ma_labelButton;
showWindow ma_labelWin;

global proc ma_changeLabel(){
string $ma_getLabel = `textField -q -tx ma_labelText`;
button -e -l $ma_getLabel ma_labelButton;

Go through the code and see if you understand it. If not, break it down. Look at the sections:

  • You check if the window exits (`window -ex ma_labelWin`). This will return 0 or 1 depending if the
    window is open or not. You don't need to write == really. Think of it like this: "If icecream..." If icecream
    exists it has to return 1.
  • window [flags] [name]
  • a layout for the window
  • textField [flags] [name]
  • button [flags] (the most important flag "-c /-command") [name]
  • the showWindow command to show the window.
  • Defining proc.
  • query the text written.
  • use the queried text to edit the label for the button.



I think it's time to go through the script now. You probably have enough knowlege to attack scripts now.
Remember that even if something here is not too clear right now you'll learn from experience. Remember
how I told you I couldn't get my head around loops? I wasn't kidding when I said it took weeks. Even when
someone explained them to me I just couldn't. Stupid, stupid, stupid... Then I started using them and
I felt more comfortable with them right away. You will learn faster by doing. Everyone knows this! Do it!

Ok, what I want the script to do is this:

  • List the objects I want to edit. I want to be able to select just some of the objects from the list too.
    I also want to be able to change the selection without reopening the window.
  • I want a layout with checkboxes for the renderStats.
  • I want a button that cycles through all the choices I made with the checkBoxes and applies the new

When I picture this script in my head it looks like this: ( quick paintover... )

I'm also writing down which commands I think I'll end up using. Programmers have their own way of scripting.
Someone likes to do all the code first and make that work before they even think about the UI, others
script the UI first and then worry about the core. I am a 3d artist and not a programmer so I tend to care more
about how thing looks, maybe a bit too much really :) But anyways, with this script I'll go from top to bottom:

window: You should ask yourself: "Does the script really need a UI?" If you don't rely on user interaction there
is no need for a UI. It could be a shelfButton instead. In this case we actually need an interface. I'll also make
sure Maya deletes my window if it exists, just like we did earlier.

if(`window -ex ma_multiAttrEdWin`)deleteUI ma_multiAttrEdWin;

window -t "final3 Multiple renderStatsEditor" -wh 280 294 ma_multiAttrEdWin;
showWindow ma_multiAttrEdWin;

You might noticed that the deleteUI-command is on the same line as the if statement and I also left the
curly braces out. When you only have ONE line to go between the curly braces you can skip them. For
beginners I reccomend you stick with the curly braces so you won't forget them later. Stick with this code for
a while:

if(`window -ex ma_multiAttrEdWin`){
deleteUI ma_multiAttrEdWin;

I gave the window a title, defined the width and heigt using the -wh flag and I also gave the window an ID. But
in Maya you will always need some sort of layout to hold anything at all. If you try to put a button in there
between the window and showWindow command you'll get this error :
// Error: line 4: Controls must have a layout. No layout found in window : ma_multiAttrEdWin //

If you hit f1 you can read more about Maya's UI controls. Under Developer resources -> Mel commands you'll
se them listed on the far right:

I'd say the most common layout is columnLayout. If we look at the sketch I drew we see that I need more
than one column, I need two ( one for the textScrollList and one for the checkBoxes. I still have to use
a columnLayout to hold it all together though so I create a columnLayout first and then the rowColumnLayout.
In a rowColumnLayout you can define how many columns you want per row:

window -t "final3 Multiple renderStatsEditor" -wh 280 294 ma_multiAttrEdWin;
rowColumnLayout -nc 2 -cw 1 152 -cw 2 120;
showWindow ma_multiAttrEdWin;

What the flag -cw does is define the width for the columns. The width for column 1 should be 152 and the
width for column 2 should be 120. These are numbers I have found best for this exact script. You need to
try out many values here and there before you find something that fits. When you create a window like this
you'll have to nest several layouts and controls. There are different ways of achieving the same looks so
basicly do it the way you feel like doing it as long as it works. This is how I set up the layouts for my window:

window -t "final3 Multiple renderStatsEditor" -wh 285 295 ma_multiAttrEdWin;
rowColumnLayout -nc 2 -cw 1 154 -cw 2 122 -h 230;
frameLayout -l "objects:" -fn "smallFixedWidthFont" -bs "etchedIn" -h 232;
textScrollList -w 150 -h 190 -ams 1 ma_multiAttrEdTSL;
button -l "update selection" -w 148;

frameLayout -l "options:" -fn "smallFixedWidthFont" -bs "etchedIn" -h 200;
columnLayout ma_optionsColumn;

showWindow ma_multiAttrEdWin;

If you execute this code you get this:

You can see how the rowColumnLayout sets the different width for the two framelayouts, I have labels for
both my frameLayouts and I also have the controls textScrollList (empty white list) and a button. The reason
I haven't put in the controls for the options-side yet is because I plan to do this in a very different way. You
can also see that I put in a new command called setParent..; What this command does it to guide us out of
the current layout and one step upwards. See this paintover:

  • The green layout is the main columnLayout. This is the first layout we put ourselves in.
  • Then we create the rowColumnLayout. Now we are inside this one and this layout is also inside the green
  • Then we create a frameLayout. This layout is inside the rowColumnLayout that is inside the green one.
    This frameLayout represents the first column in the rowColumnLayout.
  • The layouts are defined and we create a columnLayout to hold the controls. This layout is then inside
    the frameLayout. So far we have gone like this:
    So when we go back once (setParent..;) we go back to frameLayout. Then the second setParent will guide
    us back to the layout above this one again which is rowColumnLayout. Now we are ready to define the
    second column. So after the second setParent we simply write frameLayout because that's the layout
    we want for the optionsColumn. It would have been easier to see this if we named the layouts, but I
    only name the ones I know I'll be modifying later.



The content of this tutorial is copyrighted by law.
Reproduction of the content without permission
will result in legal prosecution. © 2006