PySide勉強 その五
次は、前回作ったUiを改良して
UIに変化を追加する流れを見て見ます。
新たにLISTを作成して、そこにパラメータを追加するという
流れにしてみます。
#-'''- coding: utf-8 -'''- from PySide.QtCore import * from PySide.QtGui import * from maya.app.general import mayaMixin class Form(mayaMixin.MayaQWidgetBaseMixin,QDialog): def __init__(self, parent=None): super(Form, self).__init__(parent) self.edit = QLineEdit("Your Name???") self.button = QPushButton("Push!!!") self.Sorce_list = QListWidget() layout = QVBoxLayout() layout.addWidget(self.edit) layout.addWidget(self.button) layout.addWidget(self.Sorce_list) self.setLayout(layout) self.button.clicked.connect(self.greetings) def greetings(self): self.Sorce_list.addItem(self.edit.text()) print ("Hello", self.edit.text()) if __name__ == '__main__': form = Form() form.show()
実行すると、わかりますが
ボタンの下部に空白がリストが生成されています。
文字列を入力して、ボタンを押すとリストに追加されます。
このリストは self.Sorce_list = QListWidget()
で宣言している部分で、PySideで生成された
リストGUIになります。
リスト上部のボタンを押すと、関数が走り
テキスト部分に入力された文字列を
リストに追加といった処理が行えます。
以下に簡易に説明を
self.Sorce_list.addItem(self.edit.text()) print ("Hello", self.edit.text())
関数自体は簡単なもので、入力ボックスの値を
リストにアイテムとして追加するよ!っていう
流れだけです。
一応追加した文字列を、出力もしてます。
こんな感じで追加していき、UIを作っていく。
といった感じになります。
意外とシンプルですよね。
次はこのUIの仕組みを使って、具体的なツールを作ってみたいと
思います。
Pyside勉強 その四
いままでのツールで一点おかしな部分があります。
それはウィンドウがMAYA画面の後ろにいってしまう点です。
なんでこんなことがおきるんでしょうか?
その原因はMAYAのウィンドウがPySideで
作成されているのが、起因になっています。
前の記事でも書いてますが
PySideは継承してUIを作成していきます、
そのため、MAYAウィンドウを継承せずに
UIを生成すると、MAYAウィンドウと生成UIが
並列になることになる為、裏側にUIがいってしまいます。
こんな感じでUIが立ち上がるが
MAYAのウィンドウの適当なところをクリックすると
裏にいってしまい消えてしまいます。
これを回避するため、MAYAウィンドウを継承してあげます。
やりかたは簡単です。
from maya.app.general import mayaMixin
をインポートして、クラスの第一引数に
mayaMixin.MayaQWidgetBaseMixin
を指定してあげるだけです。
こんな感じ↓
#-'''- coding: utf-8 -'''- from PySide.QtCore import * from PySide.QtGui import * from maya.app.general import mayaMixin class Form(mayaMixin.MayaQWidgetBaseMixin,QDialog): def __init__(self, parent=None): super(Form, self).__init__(parent) self.edit = QLineEdit("Your Name???") self.button = QPushButton("Push!!!") layout = QVBoxLayout() layout.addWidget(self.edit) layout.addWidget(self.button) self.setLayout(layout) self.button.clicked.connect(self.greetings) def greetings(self): print ("Hello", self.edit.text()) if __name__ == '__main__': form = Form() form.show()
実行してもらえばわかりますが
ウィンドウが後ろにいかなくなっています。
これはQDialogがMayaウィンドウの子どもになっているからです。
簡単ですね。
以降のスクリプトではこの記述は、必須ですね。
以上です。
Pyside勉強 その参
次は
Pysideの肝になる継承を含んだ例です。
こちらも前前回の記事に載っているものですね。
#-'''- coding: utf-8 -'''- from PySide.QtCore import * from PySide.QtGui import * class Form(QDialog): def __init__(self, parent=None): super(Form, self).__init__(parent) self.edit = QLineEdit("Your Name???") self.button = QPushButton("Push!!!") layout = QVBoxLayout() layout.addWidget(self.edit) layout.addWidget(self.button) self.setLayout(layout) self.button.clicked.connect(self.greetings) def greetings(self): print ("Hello", self.edit.text()) if __name__ == '__main__': form = Form() form.show()
起動するとこんな感じに
UIに文字を入力すると
入力した値が出力されるといった簡単なものです。
なんか返って来てますね。
では解説を…
class Form(QDialog):
クラスを定義しています。
クラスの説明はややこしそうなので、簡単に雛形として
処理をまとめたりできるもの。として認識してくれればと思います。
Class この部分でクラスを定義しています。
関数だとDefですね。
その後の文字列【Form】がクラス名です。
名前は予約語以外ならなんでもいいです。
(QDialog)この部分が肝です。
クラスを定義する際に、括弧内に入れるものはPysideの場合は
継承をうまい事使ってGUIを構築していきます。
今回の件でいうと、Pysideの【QDialog】(文字入力させたりメッセージ確認等を行う、一時的に開かれるウィンドウのことです。)
を継承しますよ。そして、色々カスタマイズしますよ!と宣言しています。
ちなみに、QDialogの親元はQWidgetでまたその親がQObjectになります。
こういう親子関係がベースになりますので結構重要です。
https://blog.qt.io/jp/2010/05/05/object/Qt をはじめよう! 第7回: Qt のオブジェクトモデルを理解しよう - Qt Japanese Blog
私はここではじめ学んだ気がします。
あとこの図も
ちなみに、PySideは以下の構造になっています。
※一部抜粋
[Qt QObject]
>[Qt QLayout]
>>[Qt QBoxLayout]
>>[Qt QGridLayout]
>[Qt QWidget]
>>[Qt QDialog]
>>[Qt QLineEdit]
では続けて
def __init__(self, parent=None): super(Form, self).__init__(parent)
クラス内の一番初めの2行です。
関数が記載されています。
この関数は __init__となってます。initializeの略ですが、Pythonでは
ダブルアンダースコアで括るルールがあるみたいです。
この処理自体は、クラスを実体化させる、コンストラクタになるのですが
意味合い的には、クラスの情報を初めに定義する。
という意味があり、実際クラスを実行すると
この関数が初めに実行されます。
括弧内ですが、self、parent=Noneとなってますね。
selfは言葉通り、自身。Formクラスのことを示しています。
class Form(QDialogを継承したクラスForm)を初期化しますよ。という意味です。
parent=Noneの意味は、引数parentのデフォルト値がNoneという意味になります。
そもそもこのオブジェクト(クラス)自身、新規のオブジェクトなので
当たり前ですが、親がいません。
なので、継承元のQDialogのコンストラクタ
QDialogの__init__(None)を実行する。という意味になります。
ちなみに【parent】は実はクラス継承とは関係がないみたいで
単純にオブジェクト間の親子関係を表すみたいです。
要はparent引数をNoneにした場合、QDialogが親で
【新規のオブジェクトを作成】ということになります。
※このあたり自信がないので、間違っていたら
ご指摘いただけますと、嬉しいです。
●次の行
super(Form, self).__init__(parent)
こちらは上記の続きになります。
super() は親クラスを示すためのメソッドです。
__init__() メソッドは親クラスでも、子クラスでも定義されています。
このような場合、子クラスが初期化が有線されて上書きされます。
これをオーバーライドと言います。
親クラスのメソッドや変数を呼んだり参照したいケースでsuper()を使用します。
では中身をみてみます。superのプロパティですが以下のようになります。
super(クラス, インスタンス).メソッド
詳しくは以下のサイトを…
www.lifewithpython.com
なので、置き換えると
クラスFormの親【QDialog】の初期化を実行します。
ということになり、この後に続く、QDialogに
パーツを足したりできるようになります。
長くなったので、まとめます。
def __init__(self, parent=None): super(Form, self).__init__(parent)
クラスFormの初期化メソッドで
スーパークラスのQDialogの初期化を実行し、QDialogに
パーツを仕込めるようにした。ということになります。
補足になりますが、クラス【Form】はサブクラスとなり
QDialogがスーパークラスになります。
※サブクラスとは、継承したクラスから新しく作ったクラスで
継承元のクラスがスーパークラス。
続き
self.edit = QLineEdit("Your Name???") self.button = QPushButton("Push!!!")
QDialogにテキスト入力と、ボタンを追加します。
特に説明はいらないかな?括弧の中はウィンドウに表示される文字列です。
次に上記で作成した、パーツをUIの組み込みんで行きます。
layout = QVBoxLayout() layout.addWidget(self.edit) layout.addWidget(self.button) self.setLayout(layout)
まずは
layout = QVBoxLayout()
QVBoxLayoutとは、Vertical(垂直)のレイアウトを作成します。
という意味で、要は縦にパーツを配置していくレイアウトを宣言しています。
layout.addWidget(self.edit) layout.addWidget(self.button)
垂直レイアウトに上記で記載した、テキスト入力パーツとボタンを追加。
という意味になり、UIを構築している状態になります。
self.setLayout(layout)】
上記でコマンドで、UI構築を終了して確定させます。
という意味なるので、UIがこれで構築できました。
self.button.clicked.connect(self.greetings) def greetings(self): print ("Hello", self.edit.text())
この部分は前も記載しましたので、軽く。
ボタンが押されたら、関数【greetings】を
実行。という意味になり、この関数は
テキスト入力されて値を表示する。
といったものになります。
以上で説明は終わりになります。
このスクリプトはPysideもしくはPythonの基本が詰まってるいいスクリプトですね。
Pyside勉強 その弐
続き。
ハローワールドのスクリプトはこれぐらいにして
続いてプッシュボタンについて。
これも前回記載したサイトに載っているものです。
こちらはイキナリMAYAに落とし込んだコードです。↓
# -'''- coding: utf-8 -'''- import sys from PySide.QtCore import * from PySide.QtGui import * def sayHello(): print "Hello World!" button = QPushButton("Click me") button.clicked.connect(sayHello) button.show()
実行すると、こんな感じに
ボタンを押すと、Hello World!って出力される
シンプルなものです。
以下に説明を記載します。
# -'''- coding: utf-8 -'''-
このコマンドを記載することで、UTF8にエンコードしてくれます。
記載しない限りは2バイト文字は文字化けしますので
注意が必要です。
詳しくは、こちらを参照に…
qiita.com
次、
def sayHello():
このコマンドは、def文といい、関数になります。
sayHelloは関数名になります。
この辺りはPythonの基本ですね。
一応note.nkmk.me
button = QPushButton("Click me")
前回のLabel同様に、UIパーツあたります。
QPushButtonはMAYAでいう、cmds.button()と同じです。
Pyside側のボタンを設定するメソッドです。
()中は、ボタンに表示される文字列です。
後から変更する場合は
button.setText("Push!Push!")
とします。
これでボタンの表示が変更されます。
言葉通りですが、ボタンが格納されている変数に対して
【setText】メソッドで中身を替えています。
ボタンにアイコンを仕込む時は
button.setIcon(QIcon('D:/button.jpg'))
とします。
setIconでアイコンをセットする命令を出し()内で
アイコンのファイルを指定しています。
※青い画像を指定しています。
色を変える時は、スタイルシートを使いますが
長くなるので後述します。
button.clicked.connect(sayHello)
ボタンが押された。という変更を取得し、押されたあと
関数【sayHello】に接続しています。
要はボタン押したら、関数実行しますね。って事。
MAYAだと、button(command=Function)としますが
それと同じです。
最後の一行は前と同じなので割愛。
ボタンというパーツを読み込み
クリックされたら、関数実行する。
というかなりシンプルなものです。
はい。
こんな感じです。
関数を使ったぐらいですが、これが肝なので
書いてみました。
以上です。
Pyside勉強 その壱
Pyside自体は今までも使ってきました。
が、その場しのぎでずっと使ってきました。
数日前に数見たらPysideで作ったスクリプトが20個ほど。
ただ、これらはいろんなサンプルから作っただけなので
基本で躓くことが多く、結構時間が掛かってしまってました。
ちょうど2017年の暮頃に、モチオさんが
SiShelf
github.com
を開発されていて、それに影響受けて私もやろうと
メモしたやつが見つかったので、それを再度まとめつつ
どうせなら、うやむやにしてた箇所を、一から学びなおしたいと思います。
すべて記事にすることは難しいですが、一先ず最近セレクターを
複数個作ったので、この勉強でのゴールはPysideでセレクターを作ることにします。
では、初めにいつものハローワールドから。
https://wiki.qt.io/Hello_World_in_PySide/jahttps://wiki.qt.io/Hello_World_in_PySide/ja
こちらに記載しているコードで行います。
import sys from PySide.QtCore import * from PySide.QtGui import * app = QApplication(sys.argv) label = QLabel("Hello World") label.show() app.exec_() sys.exit()
MAYAで実行すると、エラーになります。
なんでおきているかというと、MAYAでは
起動時にPysideを起動しているので
多重起動になってますよ!
ってエラーになっているわけです。
なので、それを回避する為には、以下のようにします。
app = QApplication.instance()
文字通り、インスタンス化して起動させています。
起動すると、以下の感じになります。
無事起動できました。
起動はできましたが、一個一個が説明できないと
理解したことにならないと思うので
ここは一行ずつみていきます。
コード
import sys
Python のインタプリタ、実行環境などの処理をまとめた
モジュールになります。
ファイル、パス操作など、基本的なコマンド多いので
Pythonではよく使います。
from PySide.QtCore import * from PySide.QtGui import *
PysideのGUIやそのコネクション周りのモジュールを読み込む必要があります。
それらをアスタリスクで一括読み込みしています。
アスタリスクで読み込んでいるのは、手を抜いている証拠です苦笑
app = QApplication.instance()
前述したとおり。
インスタンスを作成しています。
label = QLabel("Hello World")
PysideのQLabelというテキストや画像を表示するためのモジュールを
使って括弧内の【Hello World】をテキストとして、描画する!
という設定を行いつつ、labelという変数に格納しています。
label.show()
前述した、ラベルと表示させるコマンドです。
MAYAのShowと同じ感じです。
app.exec_()
このコマンドで、アプリケーションを実行しています。
exec_()は実行コマンドなので、インスタンスを実行する。
ということです。
sys.exit()
スクリプトのプロセスを終了させます。
正直、上記の書き方では無くても動きます。
MAYAで動かす際には
from PySide.QtCore import * from PySide.QtGui import * label = QLabel("Hello World") label.show()
このコマンド郡だけで動きます。
これは前述しましたが、MAYA上で既にPysideが動いていますので
スクリプトエディタ上では
app.exec_() sys.exit()
この二つをスクリプト実行時に、裏で実行している為です。
こんな感じで一番初歩の部分から進めていき
10回ぐらい続けばいいなぁと思います。
以上です。
Jiggleについて
使おう使おうと思って、中々手が出なかった【Jiggle】デフォーマ。
今日というかさっき、テストしたので
メモ代わりに記載。
初めに【Jiggle】とは?
→揺れに当たる。
私はこれを見て、やりたいなぁと思いました。
これは直ジオメトリですが、骨などにも使えそうだなぁと。
そこでさっきやってみました。
まずは元がこれ
JiNoggle from tommy_on on Vimeo.
これにJiggleを設定したやつ。
Jiggle from tommy_on on Vimeo.
これはJiggle_pSphere1にJiggleデフォーマを設定し
次に適当な頂点位置にロケーター【Jiggle_locator1】を置いて
pointOnPolyConstraintを実行。
※このあたりは揺れの移動値が取れればなんでもいい。
Jiggle_pSphere1の子どもにロケータ【Jiggle_locator2】を配置。
そのロケータは上記のロケーター【Jiggle_locator1】に対して、ペアレントコンストしただけです。
このロケータがバインド骨とかをドリブンすれば
いいかな?と思います。
まぁ簡単ですが、とりあえず揺れたんでOKとします。
ちなみにJiggleの設定はこんな感じにしてます。
超適当です。
これをリグに仕込むのはこれから考えますが
Softbodyより軽ければ使いみちがあるかも。
あと、個人的には【SEN_A0527】さんのベルレのやつも気になってます。。。
ベルレを使った揺れ処理ノードを作ろう! - SEN_Aのじゆうちょう
とりあえず今回はここまで。
以上です。
膝パーツの組み方
よくある事例なんですが、いつも接続で?ってなるのでメモ。
画像みたいに、ひざにパーツがついてる時があります。
特にメカ系なんかに多いんですが…
これを足の骨だけでそのまま回すと
こうなるかと思います。
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
このままだと、硬い物等で違和感が生じる為、骨を足して
処理を追加します。
※膝と同階層に
画像のように配置します。
ウェイトは繋がっていない限り、パーツに全振りします。
んで、この骨に対して接続を行います。
※デモの為、jointOrientをしていません汗・・・・
kneeの回転値Zを各【remapvalue】の【入力値】に接続し、出力値をnodeとしいう階層に接続してます。
この出力値は、追加した骨を拘束しており、ドリブンされています。
とりあえず、【TX】ノードの接続をみていきます。
基本的には画像の通り。
膝の回転値を変換して、最大は動かないように【0】にして最小の値を【-1】にしています。
このように他のチャンネルにも接続すると、
Knee_Rig from tommy_on on Vimeo.
このような挙動になります。
はじめはclampノードを使っていたんですが
clampだと、リミット時にカクッとなる為
代案を考えておりました。
いろんなデータを落としたりしてる中で、IKFKの切り替えで
【remapvalue】を使っている所を確認したので
試した所きれいにいったのでこれをつかってます。
先人達には感謝がつきませんね…
では…