2019年12月24日火曜日

QtDesignerと.uiと.pyそしてMotionbuilder

この投稿は
Windows用にPyQt使ってたけど
Motionbuilderで使いたいので
PySideで書き直してみた
という最初からPySide&Motionbuilderでやっとけよという内容です

結論から言うと
Motionbuilderでも使うならPySide使え
特に考えなくPyQtを使っていたのですが。
MotionbuilderのPythonにPySideが入っていて、PyQt4のリファレンスがほぼ無い。
というわけで使うならPySideがよさそう。

PySide 1.2.1 Reference
PyQt's Modules
以下、最初にPyQt4でuiを作成したプロジェクトをPySideに変更、その後Motionbuilderに対応させた例。
(Motionbuilderへの変更はほぼ無いに等しいけど)

PySideの導入は以下のサイトを参考にした
Python + PySide + QtDesigner で 実行ファイルを作るまで

備忘録のために作業の流れ。

1.QtDesignerで.uiを作る
2.PyQt用に.uiを.pyにコンバートする
3.実行側のpythonをPyQtを使って作る
4.PySide用に.uiを.pyにコンバートする
5.実行側のpythonをPySideを使って作る
6.PySideを使ったpythonをMotionbuilderで動くように書き換える
Motionbuilderで使うだけなら1と6だけやればいい

1.QtDesignerで.uiを作る

詳細はどこか別のサイトを参考にしてください。ここで言えるのは。
・後でアクセスしやすい名前を付けておけ
・.uiは中身はXMLなのでPyQtでもPySideでも使える
黄色い部分の名前をわかりやすくしておくとスクリプトからアクセスしやすい。
できた.ui

2.PyQt用に.uiを.pyにコンバートする

pyuic4 testWindow_UI.ui -o testWindow_UIPyQt.py
コマンドラインから.uiを.pyにコンバート。

ちなみにuiだけでいいじゃんと思っている(自分のような)人間に説明すると。
・変換した.pyに機能を追加していけば.uiという外部ファイルが不要になる
・exeにする時にも同様
・あれこれレイアウトを変更しつつ作業する時には.uiをロードして使うのが便利

自分の作業工程としては
・.uiのままレイアウト変更しつつ作業
・.pyにしてimportしてexeにしたときに外部ファイル無しで完成させる
なので実行側のpythonは.uiと.pyの両方に対応している。

3.実行側のpythonをPyQtを使って作る

作ったのがこちら
fromUi = False
このフラグがTrueの時は.uiからloadする。Falseの時は.pyからimportする。
exe化する時はFalse。
ui = None
これがuiデータの親になるのでglobalに出しておくと便利
def CB_Add():
ボタンを押した時のコールバック用
ui.listWidget.addItem(QtGui.QListWidgetItem(testList[ui.listWidget.count()]))
リストに追加する時にはQtGui.QListWidgetItemに変換して入れてやらなくてはならない。面倒。
あとlistWidget.countではなく.count()なのが地味に面倒。毎回間違える。
# ui.listWidget.removeItemWidget(ui.listWidget.item(i))
リストの項目を消す用とおぼしきremoveItemWidget()というのがあるが、どうやらうまく動作しないらしい。
del itemを使えという記事もあったが、表示から消えるだけでリスト内には残っているため後の処理で不便。
ここでは一度全部消してから書き直している。
app = QtGui.QApplication(sys.argv)
window = QtGui.QMainWindow()
このあたりは自分的にはオマジナイの意味しかない。(理解してない)
ui.toolButton_0.clicked.connect(CB_Add)
ui部品を取り出す例。名前はQtDesignerで指定した名前。(ラベルとは違う)

4.PySide用に.uiを.pyにコンバートする

pyside-uic.exe testWindow_UI.ui -o testWindow_UIPySide.py

5.実行側のpythonをPySideを使って作る

from PySide import QtGui, QtCore, QtUiTools # ☆変更
PySideにはuicが無い。(別のところにある)
# AttributeError: 'PySide.QtGui.QListWidget' object has no attribute 'isItemSelected'
        if i == ui.listWidget.currentRow():
        # ui.listWidget.removeItemWidget(ui.listWidget.item(i))
        continue
PySideではisItemSelected()ではなくcurrentRow()を使う。
また、removeItemWidget()は相変わらず使えない。
ui = QtUiTools.QUiLoader().load(os.path.join(localPath, fileName))
window.setCentralWidget(ui)
.uiファイルのロード方法が異なる。
ui.toolButton_0.clicked.connect(CB_Add)
ui要素の呼び出しはPyQt同様

6.PySideを使ったpythonをMotionbuilderで動くように書き換える

if __name__ == '__builtin__': # ☆変更
MotionbuilderのPython Editorから実行すると__name__が__main__ではなく__builtin__になるuiPath = os.path.abspath("E:/PATH/testWindow_UI.ui")
Motionbuilderだとcwdが実行したファイルと違う&cwdにあっても他のファイルを参照できない。ので、絶対パスでロードする。
別途パスを通してもよいが、毎度やるのは面倒なのでパスは決め打ち。

PyQt > PySideのスイッチは割と楽だった。
PySideをMotionbuilder用に書き換えるのもそれほど苦ではない。
けどまあ結論から言うとMotionbuilderでも使うならPySideかな。

0 コメント:

コメントを投稿