リファレンス / 3ds Max / MaxScript チートシート

rollout コントロール

  • 3ds Max
  • MaxScript
  • チートシート
MaxScript チートシート の章一覧

rollout に置くコントロールの逆引きです。どのコントロールも 定義(種類 変数名 “ラベル” パラメータ…)プロパティで値を読み書きon 変数名 イベント do で反応 の 3 点セットで書きます。 rollout 自体の作り方やメッセージボックスは 「UI・ダイアログ」章 を参照してください。

共通の書き方

rollout roDemo "Demo" width:240
(
    -- 定義: 種類 変数名 "ラベル" パラメータ...
    listbox lbx "リスト:" items:#("A", "B", "C") height:5

    -- イベント: on 変数名 イベント 引数 do
    on lbx selected i do format "% 番目: %\n" i lbx.items[i]
)
createDialog roDemo

roDemo.lbx.selection = 2     -- rollout の外からは「rollout名.コントロール名.プロパティ」
roDemo.lbx.enabled = false   -- 無効化(グレーアウト)
共通パラメータ(定義時) 意味
width: / height: 大きさ(px)。listbox などの height:行数
align:#left #center #right 横位置(既定は #center)
offset:[x,y] 自動配置の位置からのずらし
across:N 以降の N 個を横並びにする
pos:[x,y] 絶対座標。自動配置を無視 するので、他と混ぜると重なりやすい
enabled:false 最初から無効にしておく
tooltip:"..." マウスオーバーの説明(button など)
共通プロパティ(実行時) 意味
.enabled 有効 / 無効
.visible 表示 / 非表示
.caption ラベル文字列
.pos / .width / .height 位置と大きさ
  • 以降のスニペットは、特記がない限り rollout 定義の中に置く 前提です(on ... do は rollout の中でしか書けません)。

listbox(単一選択リスト)

rollout roList "listbox" width:220
(
    listbox lbx "ジオメトリ:" items:#() height:10
    button  btnRefresh "更新" across:2
    button  btnSelect  "選択"

    local nodes = #()   -- 表示名とノードを同じ並びで持つ(items は文字列しか入らないため)

    fn refresh =
    (
        nodes = geometry as array
        lbx.items = for o in nodes collect o.name
    )

    on roList open do refresh()
    on btnRefresh pressed do refresh()
    on lbx selected i do format "選択: %\n" lbx.items[i]   -- クリックで発火(i はインデックス)
    on lbx doubleClicked i do select nodes[i]              -- ダブルクリック
    on btnSelect pressed do
        if lbx.selection > 0 do select nodes[lbx.selection]   -- 0 = 未選択
)
createDialog roList
プロパティ / イベント 意味
.items 表示する文字列の配列。丸ごと差し替える
.selection 選択中のインデックス(1 始まり、0 が未選択)
.selected 選択中の文字列
on lbx selected i do クリックで選択したとき
on lbx doubleClicked i do ダブルクリック
on lbx rightClick do 右クリック
  • ⚠️ items には 文字列しか入りません。ノードを扱うときは上のように別の配列を同じ並びで持ち、インデックスで引きます。
  • ⚠️ .items を差し替えると選択が外れることがあるので、必要なら続けて .selection を設定し直します。

multilistbox(複数選択リスト)

rollout roMulti "multilistbox" width:220
(
    multilistbox mlb "ジオメトリ:" items:#() height:10
    button btnAll    "全選択" across:3
    button btnNone   "解除"
    button btnSelect "選択"

    local nodes = #()

    fn refresh =
    (
        nodes = geometry as array
        mlb.items = for o in nodes collect o.name
    )

    on roMulti open do refresh()
    on btnAll  pressed do if mlb.items.count > 0 do mlb.selection = #{1..mlb.items.count}
    on btnNone pressed do mlb.selection = #{}
    on btnSelect pressed do select (for i in mlb.selection collect nodes[i])
    on mlb selectionEnd do format "選択数: %\n" mlb.selection.numberSet   -- 選択操作が終わったとき
)
createDialog roMulti
プロパティ / イベント 意味
.selection 選択中のインデックスの BitArray(#{1, 3} など)
.selection = #{} 全解除
.selection = #{1..n} 1〜n を選択
on mlb selected i do クリックした 1 項目 のインデックス
on mlb selectionEnd do マウスを離して選択が確定したとき
on mlb doubleClicked i do ダブルクリック
  • for i in mlb.selection collect ... で選択中のインデックスを順に回せます。件数は .numberSet です。
  • ⚠️ selectedクリックした 1 件 しか教えてくれません。選択全体を扱うときは selectionEnd.selection を読みます。
dropdownlist ddl "モード:" items:#("Copy", "Instance", "Reference") selection:2
on ddl selected i do format "% (%)\n" ddl.selected i   -- .selected は文字列、i はインデックス

ddl.items = #("A", "B")   -- 差し替え
ddl.selection = 1         -- 差し替えたら選択も設定し直す

-- combobox は「入力欄 + 一覧」。一覧にない値も打ち込める
combobox cbx "サイズ:" items:#("10", "20", "50") height:5
on cbx selected i do format "一覧から: %\n" cbx.selected
on cbx entered txt do format "入力: %\n" txt        -- 入力欄の文字が変わったとき
cbx.text                                           -- 入力欄の現在の文字列

edittext(文字列入力)

edittext edt "接頭辞:" text:"Box_" fieldWidth:120
on edt entered txt do format "確定: %\n" txt   -- Enter を押した / フォーカスが外れたとき
on edt changed txt do format "入力中: %\n" txt  -- 1 文字ごと

edittext edtMemo "" height:80 labelOnTop:true   -- height: を付けると複数行
edittext edtPath "" text:"C:/temp" readOnly:true
edt.text = "Sphere_"                            -- 値の設定
  • 入力の検証や整形は entered でまとめて行うと、1 文字ごとの changed より扱いやすいです。

spinner / slider(数値)

spinner spn "高さ:" range:[0, 1000, 10] type:#worldunits fieldWidth:60   -- range:[最小, 最大, 初期値]
slider  sld "強さ:" range:[0, 100, 50] type:#integer ticks:10

on spn changed val do format "値: %\n" val            -- ドラッグ中も連続で発火
on spn buttonup do format "確定: %\n" spn.value       -- スピナのボタン / ドラッグを離したとき
on sld changed val do format "スライダ: %\n" val

spn.value = 25                -- 値の設定
spn.range = [0, 10, 5]        -- 範囲(と値)をまとめて変更
type: 意味
#integer 整数
#float 実数(既定)
#worldunits シーン単位で表示(cm など単位付き)
  • ⚠️ changedドラッグ中に何度も 呼ばれます。重い処理や undo のまとめは buttonup 側で行います。

checkbox / checkbutton / radiobuttons(オン・オフと択一)

checkbox     chk "ランダム配置" checked:true
checkbutton  ckb "ON / OFF" checked:false width:80          -- 押し込み式のボタン
radiobuttons rdo "軸:" labels:#("X", "Y", "Z") default:3 columns:3

on chk changed state do format "checkbox: %\n" state        -- true / false
on ckb changed state do ckb.caption = if state then "ON" else "OFF"
on rdo changed state do format "radio: %\n" state           -- 選んだ番号(1 始まり)

chk.checked = false
rdo.state   = 1            -- 0 にするとどれも選ばれていない状態

button / pickbutton(ボタンとシーンからのピック)

button btnRun "実行" width:100 height:28 tooltip:"選択したオブジェクトに適用"
on btnRun pressed do format "run\n"
on btnRun rightClick do format "右クリック\n"

-- pickbutton: 押すとビューポートでノードを 1 つ選ばせる
fn geomOnly o = superClassOf o == GeometryClass         -- filter: 用。true を返したものだけ拾える
pickbutton pkb "ターゲットを選ぶ" filter:geomOnly autoDisplay:true message:"対象をクリック"
on pkb picked obj do
    if obj != undefined do format "picked: %\n" obj.name   -- キャンセルで undefined が来ることがある

pkb.object          -- 最後にピックしたノード(未ピックなら undefined)
  • autoDisplay:true にすると、ピックしたノード名がボタンに表示されます。
  • filter: の関数は pickbutton より前 に定義しておきます(rollout の中の fn でも、外のグローバル関数でも可)。
colorpicker cp "色:" color:(color 255 128 0) modal:false   -- modal:false だと選択中にも changed が飛ぶ
on cp changed clr do for o in selection do o.wirecolor = clr

label lbl "状態: 待機中" align:#left
lbl.text = "状態: 実行中"

hyperlink hlp "MAXScript ヘルプ" address:"https://help.autodesk.com/" color:blue

progressbar pb color:(color 60 160 60) height:14
pb.value = 50                                   -- 0〜100

timer tmr interval:1000 active:false            -- interval はミリ秒
on tmr tick do lbl.text = "tick " + (tmr.ticks as string)
tmr.active = true                               -- 開始 / 停止
  • ⚠️ timer は rollout を閉じても止まらないことがあります。on ro close do tmr.active = false で止めておきます。

group / subrollout / dotNetControl(レイアウトと拡張)

rollout roChild "子ロールアウト" width:220
(
    spinner spnChild "子の値:" range:[0, 10, 1]
)

rollout roLayout "レイアウト" width:260
(
    group "対象"                                -- 枠で囲む(見た目だけ)
    (
        radiobuttons rdo "" labels:#("選択", "全部") default:1 columns:2
        checkbox chkHidden "非表示も含める"
    )
    button btnA "A" across:3 width:70           -- across: で横並び
    button btnB "B" width:70
    button btnC "C" width:70

    subrollout sub "サブロールアウト" height:120 width:240   -- 別の rollout を埋め込む枠
    on roLayout open do addSubRollout sub roChild            -- 子は先に定義しておく
)
createDialog roLayout
-- .NET のコントロールをそのまま置く(ListView の例)
rollout roDn "dotNetControl" width:260
(
    dotNetControl lv "System.Windows.Forms.ListView" width:240 height:120

    on roDn open do
    (
        lv.View = (dotNetClass "System.Windows.Forms.View").Details
        lv.Columns.Add "名前" 200
        for o in geometry do lv.Items.Add o.name
    )
    on lv DoubleClick sender args do                 -- イベントは on 変数名 イベント名 sender args do
        if lv.SelectedItems.Count > 0 do format "%\n" lv.SelectedItems.Item[0].Text
)
createDialog roDn

ダイアログの小技(createDialog のオプション)

try (destroyDialog roList) catch()      -- 開き直す前に閉じる(二重に開かない定石)
createDialog roList 260 320 pos:[100, 100]   -- 幅 高さ と画面上の位置
createDialog roList style:#(#style_titlebar, #style_sysmenu, #style_resizing)   -- リサイズ可能にする
createDialog roList modal:true          -- モーダル(閉じるまで呼び出し元に戻らない)

-- 複数の rollout を 1 つのウィンドウにまとめる
rf = newRolloutFloater "ツール" 280 500
addRollout roList  rf
addRollout roMulti rf rolledUp:true     -- 折りたたんだ状態で追加
-- rollout 自体のイベント
on roList open do ()                    -- 開いたとき(初期化)
on roList close do ()                   -- 閉じたとき(後片付け)
on roList resized size do ()            -- リサイズ(size は [w, h])
on roList oktoclose do queryBox "閉じますか?"   -- false を返すと閉じられない

落とし穴まとめ

  • listbox / multilistboxitems は文字列だけ。ノードは別配列を同じ並びで持ち、インデックスで引く。
  • .items を差し替えたら .selection も設定し直す。
  • multilistboxselected は 1 件ずつ。選択全体は selectionEnd.selection(BitArray)を読む。
  • spinnerchanged はドラッグ中も連続で飛ぶ。重い処理は buttonup で。
  • pickbutton はキャンセルで undefined が渡ることがある。判定してから使う。
  • pos: は自動配置を無視する。並べたいときは across: / align: / offset: を使う。
  • 同じ rollout を開き直すときは try (destroyDialog ro) catch() を先に呼ぶ。
  • timer は閉じる前に active = false にする。

関連

← MaxScript チートシート へ