mayaコマンドを使ったGUIの書き方

##**はじめに**
mayaでツールを作る際に、ツール用のGUIを作ることがあります。
MELで作る場合はMELコマンドを使用して
Pythonで作る場合はPySideを使うかmaya.cmdsやpymelからMELを呼び出して作る感じかと思います。

ツイッターとかを見ているとPythonで書く場合はPySideを使う人が多いんですかね。
今回はニッチな層を狙ってmaya.cmdsを使ってGUIを作るときに
with構文と`LayoutManager`を使うと便利だよ！というのをご紹介します。

##**GUIの例（MEL）**
maya.cmdsを使った例を説明する前にMELで作る場合は例えばこんな感じになります。

```MEL
global proc testWindow()
{
//既にGUIが存在する時に古いほうを消す処理
if(`window -ex testWindow`) deleteUI testWindow;
string $windowName = `window -title "testWindow" testWindow`;
//GUIを作成
string $tabTest = `tabLayout -innerMarginWidth 1 -innerMarginHeight 5 -scrollable false`;
string $tabTestColumn =`columnLayout -adj true -rowSpacing 10`;
    button -label "TestButton";
    button -label "TestButton"; 
    textField -tx "TestTextField" -w 500; 
    rowLayout -numberOfColumns 4 -columnWidth4 100 150 150 150 -columnAttach4 left left left left;
        button -label "TestButton";
        checkBox -label "TestCheckBox";
        checkBox -label "TestCheckBox";
        checkBox -label "TestCheckBox";
    setParent..;  
    text -label "TestText";
    textField -tx "TestTextField" -w 500;    
setParent..;
tabLayout -edit -tabLabel $tabTestColumn "Test" $tabTest;
//GUIを表示
showWindow;
}

testWindow()
```

上記のMELを実行するとこんな感じのGUIが立ち上がります。
![2019-12-02_12h30_17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529842/24afc3f9-3e82-d166-54fa-93fe64769529.png)

コードの中でGUIを作っている部分を色分けしてみます。
一番大きい赤枠がcolumnLayoutで(要素を縦に並べるレイアウトです)
青枠の所でcolumnLayout内にbuttonやtextFieldを上から順に配置していき
緑枠では一行の中にbuttonとcheckBox3つを配置しています。
MELで書く場合はGUIのレイアウト内の階層によってインデントを変えてやると
コードが見やすくなります。
![2019-12-02_12h46_23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529842/2fddcacf-1f66-b0f8-6865-1e8d8a81f5f7.png)
![2019-12-02_11h13_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529842/f9f90683-d0f6-449e-1eb7-51e59f1ea8ed.png)

##**GUIの例（maya.cmds）**
次にmaya.cmdsの書いた例です。


```python
# !/usr/bin/env python
# -*- coding: utf-8 -*-
    
import maya.cmds as cmds

def testWindow():
    #既にGUIが存在する時に古いほうを消す処理
    if cmds.window('testWindow', ex=1):
        cmds.deleteUI('testWindow')
    windowName = cmds.window('testWindow',title='testWindow')
    #GUIを作成
    tabTest=cmds.tabLayout(scrollable=False, innerMarginHeight=5, innerMarginWidth=1)
    tabTestColumn=cmds.columnLayout(adj=True, rowSpacing=10)
    cmds.button(label="TestButton")
    cmds.button(label="TestButton")
    cmds.textField(w=500, tx="TestTextField")
    cmds.rowLayout(numberOfColumns=4, columnAttach4=('left', 'left', 'left', 'left'), columnWidth4=(100, 150, 150, 150))
    cmds.button(label="TestButton")
    cmds.checkBox(label="TestCheckBox")
    cmds.checkBox(label="TestCheckBox")
    cmds.checkBox(label="TestCheckBox")
    cmds.setParent('..')
    cmds.text(label="TestText")
    cmds.textField(w=500, tx="TestTextField")
    cmds.setParent('..')
    cmds.tabLayout(tabTest, edit=1, tabLabel=(tabTestColumn, "Test"))
    #GUIを表示
    cmds.showWindow()

if __name__ == '__main__':  
    testWindow()
```
maya.cmdsの場合(とうよりpythonの場合)インデントがずれるとエラーになるので
レイアウト内の階層に合わせてインデントを変えてやるということができません。
さらに言うと`cmds.setParent('..')`も何度も出てくるので消したいところです．．．
ということでここからが**今回の本題です！**

##**with構文とLayoutManagerを使用する**
with構文とmayaの中にデフォルトである`LayoutManager`というモジュールを組み合わせて使用します。
with構文は主にファイルのオープンとクローズの時に使用するものです。
withを使わない場合は↓のように書きますが

```python
f = open("test.txt", "r")
print(f.read())
f.close()
```
withを使うと`f.close()`の部分を省略することができます。
さらに都合の良いことにwith文の下の行はインデントを空ける決まりになっています。

```python
with open("test.txt", "r") as f:
    print(f.read())
```

`LayoutManager`はwith構文のこういった仕組みを利用して
インデントを自由に変えれるようにするモジュールです。
maya.common.uiのライブラリの中に含まれているので下記のようにしてインポートします。

```python
from maya.common.ui import LayoutManager
```
`LayoutManager`を使ってmaya.cmdsを使ったGUIの例を書き換えると下記のようになります。

```python
# !/usr/bin/env python
# -*- coding: utf-8 -*-
    
import maya.cmds as cmds
from maya.common.ui import LayoutManager

def testWindow():
    #既にGUIが存在する時に古いほうを消す処理
    if cmds.window('testWindow', ex=1):
        cmds.deleteUI('testWindow')
    windowName = cmds.window('testWindow',title='testWindow')
    #GUIを作成
    tabTest=cmds.tabLayout(scrollable=False, innerMarginHeight=5, innerMarginWidth=1)
    with LayoutManager(cmds.columnLayout(adj=True, rowSpacing=10)) as tabTestColumn:
        cmds.button(label="TestButton")
        cmds.button(label="TestButton")
        cmds.textField(w=500, tx="TestTextField")
        with LayoutManager(cmds.rowLayout(numberOfColumns=4, columnAttach4=('left', 'left', 'left', 'left'), columnWidth4=(100, 150, 150, 150))):
            cmds.button(label="TestButton")
            cmds.checkBox(label="TestCheckBox")
            cmds.checkBox(label="TestCheckBox")
            cmds.checkBox(label="TestCheckBox")
        cmds.text(label="TestText")
        cmds.textField(w=500, tx="TestTextField")
    cmds.tabLayout(tabTest, edit=1, tabLabel=(tabTestColumn, "Test"))
    #GUIを表示
    cmds.showWindow()

if __name__ == '__main__':  
    testWindow()
```

インデントの位置を変わったのと`cmds.setParent('..')`が
なくなったのでちょっとだけ見やすくなりました！

##**おわりに**
PySide使うので要らないですとかインデント空けたほうが見にくいじゃん
と思われた方もいるかも知れませんが
ネットで検索しても`LayoutManager`出てこなかったのでご紹介させて頂きました。
そんなに便利な機能ではないですが良ければ使ってみてください！