【補完】[PySide] QtDesignerで遊ぼう

PySideの勉強（に伴うQtDesignerの勉強）でお世話になっているこちらの記事

**[PySide] QtDesignerで遊ぼう** @ *mtazmi-Lab*
http://mtazmi-lab.blogspot.jp/2013/01/QtDesiner.html

につきまして、
ここで作られているUIを受けて、情報を取得したりなんか発行したりするスクリプトを書いてみたいと思います。

mtazmiさんありがとうございます、お世話になっておりますm(_ _ )m

# 承前

どういうことかと申しますと、
こちらの記事は **QtDesignerでのUIづくり** についてのステキ記事で、
その前後記事でもPySideならびにQtDesignerを使った事例を解説しておられます。

ただ、当該記事に登場するUIそのものについては動作部分が用意されておりませんでしたので、
MAXリスペクトしつつその点を補完した小ネタを書かせていただきたい、
と思った次第です。

## 補足

前後の記事はこちらです。ぜひあわせてどうぞ

[PySide] PySideで遊んでみるよ 
http://mtazmi-lab.blogspot.jp/2012/12/pythonPySide01.html

[PySide] UIからいろいろな値を取ろう
http://mtazmi-lab.blogspot.jp/2013/01/pysidegetvalue.html

前者は今回の路線に比較的近く、
後者はQtDesignerを用いないPySideによるスクラッチです

# UIの準備

元記事に添ってUIを作成しましょう。
ちなみにQtDesignerはMayaインストールフォルダの``bin``以下にいる
**designer.exe** がそれです。

```
C:\Program Files\Autodesk\Maya{ver}\bin\designer.exe
```

しんちょく1
![01.png](https://qiita-image-store.s3.amazonaws.com/0/102581/4a98417f-0d5e-f43f-ea82-93a032fa0a05.png)


しんちょく2
![02.png](https://qiita-image-store.s3.amazonaws.com/0/102581/9f364b97-8056-6d2c-f970-50ff8c3441f5.png)


できました
.uiファイルをよきところに保存します。
ファイル名はここでは``mayapyAdCl.ui``としています。

# 動作部

動作部を作っていきます。

まずもと記事のスクリプトがこちら

```python
# -*- coding: utf-8 -*-
 
import os
import sys
 
from PySide import QtCore, QtGui
from PySide.QtUiTools import QUiLoader
 
CURRENT_PATH = os.path.dirname(__file__)
 
#----------------------------------------------------------------------------
## GUIを作るクラス
class GUI(QtGui.QMainWindow):
 
    def __init__(self, parent=None):
        super(GUI, self).__init__(parent)
        loader = QUiLoader()
        uiFilePath = os.path.join(CURRENT_PATH, 'mayapyAdCl.ui')
        self.UI = loader.load(uiFilePath)
        self.setCentralWidget(self.UI)
 
#------------------------------------------------------------------------------ 
## GUIの起動
def main():
    app = QtGui.QApplication(sys.argv)
    app.setStyle('plastique')    # ← ここでスタイルを指定
    ui = GUI()
    ui.show()
    sys.exit(app.exec_())
 
 
if __name__ == '__main__':
    main()
 
#-----------------------------------------------------------------------------
# EOF
#-----------------------------------------------------------------------------
```

これを先程の .ui と同じとこに保存します。
名前は ``mayapyAdCl.py`` としておきます。

## 動作部を追加

元記事のひとつまえの記事を参考に、
あとPySideのドキュメントも眺めながら、下記のようにしてみます。

```python
# -*- coding: utf-8 -*-

from PySide import QtCore, QtGui
from PySide.QtUiTools import QUiLoader

import maya.cmds as cmds
from maya.app.general.mayaMixin import MayaQWidgetBaseMixin

CURRENT_PATH = os.path.dirname(__file__)

#----------------------------------------------------------------------------
## GUIを作るクラス
class GUI(MayaQWidgetBaseMixin, QtGui.QMainWindow):
 
    def __init__(self, parent=None):
        super(GUI, self).__init__(parent)
         
        # uiファイルのロード
        loader = QUiLoader()
        uiFilePath = os.path.join(CURRENT_PATH, 'mayapyAdCl.ui')
        self.UI = loader.load(uiFilePath)
        self.setCentralWidget(self.UI)
         
        # ウインドウのタイトルを指定
        self.setWindowTitle(u'UIのサンプルだよ')
        # ウインドウのサイズを指定
        self.resize(256, 128)
         
        # UI要素にシグナルを追加
        self.setSignals()
 
    #----------------------------------------
    ## シグナルの登録
    # @param None
    # @return None
    def setSignals(self):
        # applyボタンを押したときの動作
        self.UI.apply_btn.clicked.connect(self.doIt)
        # apply and closeボタンを押したときの(ry
        self.UI.applyClose_btn.clicked.connect(self.doIt_close)
        # closeボタン(ry
        self.UI.close_btn.clicked.connect(self.close)

    ## チェックが入ってたらロックする
    def doIt(self):
        chbxState = {
                     'tx':self.UI.tx_chbx.isChecked(),
                     'ty':self.UI.ty_chbx.isChecked(),
                     'tz':self.UI.tz_chbx.isChecked(),
                     'rx':self.UI.rx_chbx.isChecked(),
                     'ry':self.UI.ry_chbx.isChecked(),
                     'rz':self.UI.rz_chbx.isChecked(),
                     'sx':self.UI.sx_chbx.isChecked(),
                     'sy':self.UI.sy_chbx.isChecked(),
                     'sz':self.UI.sz_chbx.isChecked()
                    }
        
        objs = cmds.ls(sl=True)
        if not objs:
            print 'no object selected...'
            return
            
        for obj in objs:
            for ch in chbxState:
                attr = '.'.join([obj,ch])
                cmds.setAttr(attr,lock=False)
                if chbxState[ch]:
                    cmds.setAttr(attr,lock=True)

    ## doItした上でclose
    def doIt_close(self):
        self.doIt()
        self.close()



#------------------------------------------------------------------------------ 
## GUIの起動
def main():
    app = QtGui.QApplication.instance()
    ui = GUI()
    ui.show()
    
    return ui
 
 
if __name__ == '__main__':
    main()
 
#-----------------------------------------------------------------------------
# EOF
#-----------------------------------------------------------------------------
```

チェックボックスが入ってるかどうかを取得して、入ってたらそのチャンネルをロックする、という例です。

## 実行

```python
import sys
sys.path.append('path/to/your/scripts')

import mayapyAdCl

myWin = mayapyAdCl.main()
```

.uiおよび.pyを置いたところにパスを通して、
importして実行します。



# 備考

## QApplication

元記事はpython.exeに投げる内容ですが、ここではMaya上での実行を考えているため、``QApplication``のインスタンスを取る箇所を変えておく必要があります。

具体的には…

```python
app = QtGui.QApplication(sys.argv)
# Error: A QApplication instance already exists.
# Traceback (most recent call last):
#   File "<maya console>", line 1, in <module>
# RuntimeError: A QApplication instance already exists. # 
```

このようなエラーが起きてしまうので

```python
app = QtGui.QApplication.instance()
```

こういう風に書き換えておきます。
あわせて``sys.exit(app.exec_())``もここでは削除するかコメントアウトしておきましょう。

## mayaMixin

作ったウィンドウをMayaのメインウィンドウに親子付けしておかないと、
後ろに隠れるシャイな子になってしまいます。

かつてはshibokenをつかってポインタ取って云々というしきたりがありましたが、
mayaMixinを活用すると、その記述を省けます。

```python
from maya.app.general.mayaMixin import MayaQWidgetBaseMixin
```

インポートして

```python
class GUI(MayaQWidgetBaseMixin, QtGui.QMainWindow):
```

継承します。

参考：
http://help.autodesk.com/view/MAYAUL/2017/JPN/?guid=__files_GUID_66ADA1FF_3E0F_469C_84C7_74CEB36D42EC_htm

## mainのreturn

main関数に``return ui``というのを足しています。
これを受け取っておくと、UI作成中のデバッグが捗るかと思います。

## close

ウィンドウを閉じるのには
QMainWindowにもとからあるメソッドを使います。

setSignals関数とdoIt_close関数内で使っていますが、
ほかのUI要素を ``self.UI.tx_chbx`` などとしているのと同じノリで
うっかり``self.UI.close()`` と書かないよう注意してください。

# おわりに

元記事のステキさあっての補足であります。

どなたかのお役に立てれば幸いです。
（動かない等へんなところがあれば教えてください。。。）

次はmono_gさんの記事 **「Mayaのマテリアルのこねこね」** です。
http://qiita.com/mono-g/items/520f4967356456eb4cc5
※『次は』といいつつmono_gさんの記事のほうが先に公開されてますが！大遅刻すみません(汗