2020/06/02
備忘録:QAbstractSliderとundo
こんにちは、BACKBONEのゆはらです。
今回の内容は、PySideのQAbstractSliderの数値の変化が
「インタラクティブにmayaシーンへの影響を与える時」のundoについての備忘録です。
1.テストシーンとGUIの用意
■ テストシーン
ご説明用として、ポリゴンフェイスにpolyExtrudeFaceを実行したものをテストシーンとして使用します。
スライダー値が動く毎にpolyExtrudeFace.localTranslateを変化させるものを目指します。
■ 簡単なスライダーGUIを作成
スライダーと、スライダーの数値を可視化するためのスピンボックスがあるGUIを用意しました。
2.完成イメージ
スライダーには、下記の機能を実装しようと考えました。
機能1.スライダー制御時は、スライダーの数値変化がシーンに影響し続ける。
機能2.スライダーのハンドルを離したとき(マウスリリース時)に、スライダーは初期値の0.0に戻る。
機能3.undo実行時には、スライダー制御時の細かな数値変化をundoの待ち行列に入れたくない。
…でき上がったものがこちらです。
機能1.左にある赤ロケーターのポジションへ、スライダー操作で位置を合わせていきます。
機能2.スライダーからマウスリリースしたときに、スライダーは初期値の0.0に戻ります。
機能3.その後undoを実行しても、スライダー制御中の数値変化はundoの対象にはなっていません。
失敗作はこちらです。
【機能3】のスライダー制御時の細かな数値変化が、すべてundoの待ち行列に入っています。
そのためundoを連打しても、なかなかスライダーを制御する前の状態に戻りません…!
この状態からよい具合にundoできるスライダーにするために、色々と試行錯誤しました。
undoについてはcmds.undoInfoにある openChunk/closeChunk フラグを使用します。
このフラグは、openChankしてからcloseChankするまでの間に行われた処理を「ひとかたまり」として
undoの待ち行列に入れることができます。
「チャンク=かたまり」という意味から考えると、分かりやすいフラグ名です。
今回作成するスライダーにもcmds.undoIndo(openChunk/closeChunk)を設定します。
どのタイミングでopenChunk/closeChunkすれば求めるスライダー挙動に近づけるのか、
つまりは、スライダーからsignalsが発生するタイミングを見ていきます。
3.QAbstractSliderのsignalsとそれぞれの発生条件
今回の挙動に関係ありそうなsignalsについて、
実際にスライダーを制御して確認すると下記のようになっていました。
[A] スライダーのハンドルをクリック→ドラッグで数値を変える
sliderPressed, [sliderMoved, valueChanged](ドラッグで連続発生), sliderReleased
[B] ハンドル以外の部分をクリックで数値を変える
valueChanged, sliderPressed, sliderReleased
[C] ハンドル以外の部分をクリック→ドラッグで数値を変える
valueChanged, sliderPressed, [sliderMoved, valueChanged](ドラッグで連続発生), sliderReleased
sliderMoved, valueChanged はマウスドラッグ時に連続で発生するようです。
このsignalsの発生状況を参考に、作成したいスライダー挙動に合わせていきます。
4.スライダーの挙動を入れる
■openChunk/closeChunkのタイミング
ドラッグした場合の[A][C]ではその間に[sliderMoved, valueChanged]が入っており、
スライダー制御中の数値変化がこれに該当します。
なのでsliderPressed、sliderReleasedにそれぞれopenChunk/closeChunkすればよさそうです。
■シーンに影響を与える関数をどこで実行するか
[A][B][C]すべてに共通しているsignalsは、sliderPressedとvalueChanged です。
このうちマウスドラッグでの数値変化を追えるのはvalueChangedですが、
[B][C]の場合、sliderPressedより先にvalueChanged が呼ばれています。
そのためvalueChangedでdoit関数を実行してしまうと、sliderPressed時に(openChunkする前に)
doit関数が実行されることになり、undo時に望ましくない挙動となってしまいます。
なので、doit関数はsliderPressedとsliderMovedの両方で実行しました。
結果的に、[A][C]ではsliderPressedとsliderMovedで、2回doit関数が実行されていることになります。
これはスライダーを動かし始めたときの一度だけなのと、
openChunk/closeChunkでundoがひとかたまりになっているのでよしとしました。
★最後に
記事を書いている時に気が付いたのですが、
QAbstractSlider上でマウスのホイールを回すとvalueChangedのみが呼ばれるようです。
記事中ではこの挙動は全く考慮できていませんのでご了承ください。
この件につきましては、私の宿題ということで今回は〆とさせていただきます……!
まとめ
このスライダーは、「頂点単位でのコピーウェイトツール」を開発するときに使用しました。
コピーウェイトツールのGUIでは、スライダーでウェイトのブレンド値を調整したいという目的がありました。
フェイシャルのウェイト調整など、細かな調整が必要な場面で効率よく作業できるため、
スライダーにして良かったと実感しています。
スライダー付きのGUI、おすすめです。
※免責事項※
本記事内で公開している全ての情報について、その完全性、正確性、適用性、有用性等いかなる保証も行っておりません。
これらの情報のご利用により、何らかの不都合や損害が発生したとしても、当社は何らの責任を負うものではありません。
自己責任でご使用ください。