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

PySideのQCompleterを使ったTABメニューもどき

この記事はMaya Advent Calendar 18日目の記事です。

タブメニュー,良いですよね。
世の中のノードベースアプリのほとんどはタブメニューがついてます。 Mayaのノードエディタ、Nuke, Houdini, wrap3D, 大抵Tabキーを押せばサーチフィールドがでて、欲しいコマンドはそこから呼び出せます。 素晴らしいです。 むしろノードしか呼び出せないのが辛い。 すべてをそこから呼び出したい。

というわけで

今回はQtのQCompleterクラスを使ってタブメニュー風コマンドランチャー的なものを作ってみます。

今回のコードはQt.pyを使用します。

まずはウィンドウを作ります。

import Qt
from maya import OpenMayaUI

try:
    import shiboken
except ImportError:
    import shiboken2 as shiboken


class Gui(Qt.QtWidgets.QWidget):

    def __init__(self, parent=None):
        super(Gui, self).__init__(parent)

        self.setAttribute(Qt.QtCore.Qt.WA_DeleteOnClose)
        self.setWindowFlags(Qt.QtCore.Qt.Tool)

        self.lineEdit = Qt.QtWidgets.QLineEdit()
        self.lineEdit.returnPressed.connect(self.execute)

        layout = Qt.QtWidgets.QBoxLayout(Qt.QtWidgets.QBoxLayout.TopToBottom)
        layout.addWidget(self.lineEdit)
        self.setLayout(layout)

def getMayaWindow():
    ptr = OpenMayaUI.MQtUtil.mainWindow()
    return shiboken.wrapInstance(long(ptr), Qt.QtWidgets.QWidget)


def main():
    window = Gui(getMayaWindow())
    window.show()


if __name__ == "__main__":
    main()


はい、できました。

次にQCompleterを作ります。

items = ["Sphere", "Cube", "Plane", "Cylinder"]
completer = Qt.QtWidgets.QCompleter(items)
completer.setCaseSensitivity(Qt.QtCore.Qt.CaseInsensitive)

補完リスト作り、QCompleterオブジェクトを作るときに引数としてそれを渡してあげます。 大文字小文字を区別しない場合はCaseInsensitiveをセットします。

self.lineEdit.setCompleter(completer)

そしてこれをQlineEditのsetCompleterメソッドでセットします。

この時点で、ウィンドウを表示して試しに ’c’ と入力すると 画像のように補完候補が表示されます。

あとはキーが入力されエンターキーを押されたときに、そのキーに基づいたコマンドが実行されるようにします。

やり方はいろいろあると思いますが、今回はキーワードと関数がセットになった辞書を使用します。

class Commands(object):

    def __init__(self):
        self.cmdsDict = {
            'sphere': self._polySphere,
            'cube': self._polyCube,
            'plane': self._polyPlane,
            'cylinder': self._polyCylinder}

    def _polySphere(self):
        cmds.polySphere()

    def _polyCube(self):
        cmds.polyCube()

    def _polyPlane(self):
        cmds.polyPlane()

    def _polyCylinder(self):
        cmds.polyCylinder()

コマンドを含んだクラスと辞書を作り、それをLineEditのreturnPressedシグナルで繋ぎます。Guiクラスの中に実行用メソッドを作ります。

def execute(self):
    key = self.lineEdit.text()
    cm = Commands()
    cm.cmdsDict[key.lower()]()
    self.close()

(シグナル等、UIのそのあたりのことはAdvent Calendar13日目参照)

これでほぼ完成です。

実行結果はこのような感じになります。

最終的なコードはこちら

タブメニューというくらいなのでTabキーで呼び出したいところですが、ホットキーエディタではTabキーへのアサインができません。Qt側からTabキーの挙動を上書きすることはできますが、MayaでTabキーは意外と使うのでおすすめはしません。

あとはこれをベースにフレームレス(Advent Calendar2日目参照)にしたり、モデルにQSortProxyModelを使ったり(AdventCalendar14日目参照)、なんやかんやでこのような形になり、

さらにどうにかこうにかで超進化するとこうなります。
Cosmos by Martin Gunnarsson.

一応自分でも随分前から自作物(Rush)を使っていますが低機能よくいえばシンプル、そしてLinuxMaya2016以降では何故か動いてくれない笑

というわけでこの手のツールをお探しであればCosmos,おすすめです(といいつつ自分は使ったことがない)
作ってみるのも楽しいでしょう。

余談ですがこのMartin Gunnarsson氏とは一時期同じフロアで働いていました。 しかしチキンな僕は話しかけれず、気づいたら彼は会社を去っていた。

まとめ

QCompleterは導入が簡単なわりに効果があるのでおすすめ。

また、この18日目はもともとrateionnさんの枠だったものを急遽譲って頂いたものです。ありがとうございました。しかし急いで書き起こした為、ところどころ「なんやかんや」とか「〇〇日目参照」などかなり端折ってしまいましたが、飛行機の時間が目の前に迫っている現在、これが限界です。すいません。

この記事が公開されるころ、僕はきっと空の彼方を飛んでいることでしょう。

おわり