2016年05月24日
3ds Max 2016の新機能を調べてみた その93 3dsmax 2016
引き続き「Maxクリエーショングラフ」の「MCG_lookAt」コントローラのパラメータロールアウトについて調べてみたい。
前回は単純なサンプルをもとに「Remove Selected」ボタンの動作を調べてみた。今回は「MCG_lookAt」コントローラの方の「Remove Selected」ボタンを調べてみたい。
「Remove Target」ボタンが押された時に呼び出されるハンドラは以下の通り。
on removeFromList_Targets_UI pressed do with undo label:"Remove Targets" on (
local indicies = mcgAPOps.GetSelectionIndices Combined_UI
mcgAPOps.INodeA_RemoveFromList Combined_UI Targets_Tab
for index in indicies do
(
if index < Weights_Tab.Count do deleteItem Weights_Tab (index+1)
)
)
太字の部分はデフォルト状態の前回のものと同様のコードになっていて、「Combined_UI」の「ListView」コントロールのリストで選択されたアイテムの番号を調べて対応する「Targets_Tab」の要素を削除するようになっている。
「Targets_Tab」が変更されたら自動的に「on Targets_Tab tabChanged」ハンドラが呼び出されて「Combined_UI」の方に「Targets_Tab」の変更を反映しようとする事になる。
on Targets_Tab tabChanged action index count do
(
Targets_List.clear()
if (paramsOpen) do (
this.params.FilltargetsListView()
if (action == #insert) then (
local sel = #()
append sel (index - 1)
this.params.SelectListviewTargets sel
)
else if (action == #append) then (
local sel = #()
append sel (Targets_Tab.Count - 1)
this.params.SelectListviewTargets sel
)
)
)
でも「Combined_UI」は「Weights」欄もあって、これに対応する「Weights_Tab」の方も「Combined_UI」で選択されているアイテムに対応して削除する必要がある。そこで「Targets_Tab」の処理を始める前に
local indicies = mcgAPOps.GetSelectionIndices Combined_UI
を実行して「indicies」に「Combined_UI」で選択されているアイテムの番号の配列を取得して、
for index in indicies do
(
if index < Weights_Tab.Count do deleteItem Weights_Tab (index+1)
)
の部分で一気に「Weights_Tab」の対応する要素を削除している。当然こっちの変化に対しても「on Weights_Tab tabChanged」ハンドラが呼び出されて「Combined_UI」の方に「Weights_Tab」の変更を反映しようとする。
on Weights_Tab tabChanged action index count do
(
Weights_List.clear()
if (paramsOpen) do
this.params.FilltargetsListView()
)
以上を見て行くと、だったら「mcgAPOps.INodeA_RemoveFromList 」なんか呼び出さないで上の「for」文の中で一緒に「Targets_Tab」も削除しちゃえばいいじゃないと思うところだ。実際「mcgAPOps.INodeA_RemoveFromList 」の中でさらに「mcgAPOps.GetSelectionIndices Combined_UI」が呼び出されていたりして処理がダブったりしている。
ただコードをよく眺めてみると、「Tab」の変更ハンドラの中から呼び出されて「ListView」を更新する「FillTargetsListView」ファンクションの中では、現在の「Targets_Tab」と「Weights_Tab」の要素数が等しいかどうかをチェックしていて、2つが等しい時しか「ListView」の更新が行われないようになっている。
fn FillTargetsListView = (
global theListView = Combined_UI
local theRange = #()
local lineNumber = 1
if (Combined_UI != undefined) do ( Combined_UI.Items.Clear()
if (this.Targets_Tab.Count == this.Weights_Tab.Count) do
(
for o in this.Targets_Tab do
(
local li = dotNetObject "System.Windows.Forms.ListViewItem" (mcgAPOps.INodeToStringFunc o)
li.ToolTipText = (mcgAPOps.INodeToStringFunc o)
local subli = li.SubItems.add (this.Weights_Tab[lineNumber] as string)
append theRange li
lineNumber = lineNumber+1
)
Combined_UI.Items.AddRange theRange
)
)
)
「on removeFromList_Targets_UI」内の処理で「Targets_Tab」と「Weights_Tab」の要素数が同じになるのは「Targets_Tab」も「Weights_Tab」も「ListView」で選択されている要素が全て削除された時だけになるので、「FillTargetsListView」は「Targets_Tab」や「Weights_Tab」が1つ変更されるたびに呼び出されるけど、実際に「ListView」を更新するのは2つの「Tab」の不要な要素の削除が全て終わった時だけってことになる。もしfor文のループ内で2つの「Tab」の要素を1つずつ削除していくループにしたら2つの要素数はループ1回ごとに等しくなり、「ListView」の更新が頻繁に起きることになる。もちろんもう少し効率のいいコードには出来ると思うけどね。
続きはまた次回。