Maresfield イギリスの飯、別にマズくないよ

Mayaで実行したPythonの関数をGキーでリピート可能にしたい

例えばこんな感じのGUIでCREATEボタンを押すとデフォルトのキューブを作るツールがあったとする。このツールを起動してすかさずGキーを押すと、キューブは作られず、ウィンドウがリロードされる。そうじゃなくてGキーを押し続ける限りキューブを作りまくってほしい。

maya.cmdsならiconTextButtonに”commandRepeatable”オプションがあるのでTrueにすればリピートしてくれる。 (iconTextButtonにはあるのに何故かbuttonにはこのオプションがない。。。)

ではPyQt/PysideでUIを作ったらどうすればいいのか、と思ってぐぐってみたらいくつかヒントがでてきた。

Python in Maya - How to make commands repeatable and undoable

ただこれは最終的にMELで実行するのだけど、これをPyQtのコネクト文にそのまま入れても実行できなかった。

記事を見るに、どうやらrepeatLastというコマンドが重要らしいけどこれがオンラインドキュメントに乗ってない。 一応スクリプトエディタ内のヘルプでオプションは見られる。

このrepeatLastはそれ以外にも問題があるようで http://forums.cgsociety.org/archive/index.php/t-940975.html によるとPythonではうまく機能しないと。

MELで問題が無いのならrepeatLastコマンドを実行するプロシージャを先に作ってあげて、Pythonの関数とそのプロシージャを同時に実行し、繰り返して欲しい関数名をrepeatLastのaddCommandStringに渡してやればいいのでは?と思って試したのが下

from PyQt4 import QtCore
from PyQt4 import QtGui
from pymel.all import mel as pa
from maya import cmds
from maya import mel
from maya import OpenMayaUI
from functools import partial
import sip


mel.eval("""
global proc callLastCommand(string $function)
{
    repeatLast -ac $function -acl "blah-blah....";
}
""")


def getMayaWindow():
    pointer = OpenMayaUI.MQtUtil.mainWindow()
    return sip.wrapinstance(long(pointer), QtCore.QObject)


class TestDialog(QtGui.QDialog):

    def __init__(self, parent=getMayaWindow()):
        QtGui.QDialog.__init__(self, parent)

        self.setWindowTitle("TestDialog")

        self.pushButton1 = QtGui.QPushButton("CREATE", parent=self)
        self.connect(self.pushButton1, QtCore.SIGNAL(
            "clicked()"), partial(self.runCmds, 1))

        self.pushButton2 = QtGui.QPushButton("EDIT", parent=self)
        self.connect(self.pushButton2, QtCore.SIGNAL(
            "clicked()"), partial(self.runCmds, 2))

        self.layout = QtGui.QBoxLayout(QtGui.QBoxLayout.TopToBottom, self)
        self.layout.addWidget(self.pushButton1)
        self.layout.addWidget(self.pushButton2)

    def runCmds(self, num):
        className = self.__class__.__name__
        if num == 1:
            self.createCube()
            pa.callLastCommand("""python(\"%s().createCube()\")""" % className)
        elif num == 2:
            self.splitEdge()
            pa.callLastCommand("""python(\"%s().splitEdge()\")""" % className)

    def createCube(self):
        cmds.polyCube()

    def splitEdge(self):
        cmds.SplitEdgeRingTool()


if __name__ == "__main__":
    dialog = TestDialog()
    dialog.show()

本来の動かしたい関数(createCube, splitEdge)とは別に、それらとrepeatLastを実行するプロシージャ(callLastCommand)の両方を実行する関数(runCmds)を用意してやることで、スマートとは言えないが一応求める挙動にはなった。