チュートリアル > ActiveX コントロールの使用 > ListView ActiveX コントロールを使用した選択オブジェクト検査プログラムの開発 - 第 2 部 |
この 2 つ目のチュートリアルでは、第 1 部で定義した Listview ActiveX コントロールをカスタマイズし、選択セットが変更されたときに表示が自動的に更新されるようにします。
ActiveX コントロールは、DotNet フレームワークとそのコントロールを考慮して、最新バージョンの Microsoft Windows オペレーティング システムで非推奨となりました。
MAXScript では引き続き ActiveX コントロールがサポートされますが、これらは MAXScript にアクセス可能なシステムにインストールおよび登録する必要があります。
ActiveX コントロールの代わりに、MAXScript では、3ds Max 9以降において DotNet コントロールがサポートされます。
「ActiveX ListView コントロールの DotNet ListView コントロールへの変換」を参照してください
MAXScript ロールアウト内の ActiveX コントロール
macroScript のスコープ (この場合はコールバック スクリプト) の外からロールアウトをアクセスできるように、ロールアウト変数をグローバルとして定義します。
rollout listview_rollout "ListView Selected" ( fn initListView lv = ( lv.gridLines = true lv.View = #lvwReport lv.fullRowSelect = true lv.backColor = color 225 215 210
Listview の backColor プロパティに新しいカラーを割り当てます。
Listview に用意されているチェックボックスを使用可能にして、ノードレベルのレンダリング可能プロパティを表すために使用します。
layout_def = #(#("On",28), #("Object Name",120), #("Object Class",80), #("Verts",45), #("Faces",45), #("Material",120))
既存のレイアウト定義配列を拡張します。列の名前だけを格納するのではなく、列の名前と幅の両方のサブ配列を格納します。将来、太字のブール値フラグ、テキストのフォアグラウンド カラーなど、列ごとにデータを追加して格納することもできます。
ユーザ変数を 2 つ定義します。1 つには最初の列のアドレスが含まれ、もう 1 つには列幅の設定を行う Listview の Windows ハンドルに送るメッセージ id が含まれます。ここは「難解な部分」であり、一般的な Microsoft Windows および ActiveX コントロールのプログラミングに関する文献に説明があります。ここでは、単純にここに示されているとおりに使用してください。
for i = 0 to layout_def.count-1 do windows.sendMessage lv.hwnd LV_SETCOLUMNWIDTH i layout_def[1+i][2]
0 から列数マイナス 1 までループします。 windows.sendMessage メソッドでは列のインデックスが 0 から始まることを前提としていますが、MAXScript の配列のインデックスは 1 から始まるためです。
windows.sendMessage メソッドには、ActiveX コントロールの Windows ハンドル (lv.hwnd)、送信するメッセージ、幅を設定する列のインデックス、および幅の値を指定します。 幅の値は、インデックスが 1 から始まる配列のインデックス(i+1)のサブ配列の 2 つ目の項目に格納されています。
Listview にデータを入力する前に、必ずリストを空にします。ここでは、ダイアログ ボックスを閉じてから再び開くのではなく、瞬時にリストが更新されるようになっているためです。
最初の列にはチェックボックスだけが入っています。現在のオブジェクトのノードレベルの .renderable プロパティから返されたブール値を、.checked プロパティに設定します。
以前は最初の列であったオブジェクト名の列が 2 番目の列になったため、サブリスト項目を作成します。
サブリスト項目の .text プロパティに、前と同じようにオブジェクトの名前を設定します。
sub_li = li.ListSubItems.add() sub_li.text = (classof o) as string sub_li = li.ListSubItems.add() sub_li.text = try((o.mesh.numverts) as string)catch("--") sub_li = li.ListSubItems.add() sub_li.text = try((o.mesh.numfaces) as string)catch("--") sub_li = li.ListSubItems.add() sub_li.text = (o.material) as string ) ) activeXControl lv_objects "MSComctlLib.ListViewCtrl" width:490 height:190 align:#center on listview_rollout open do ( initListView lv_objects fillInSpreadSheet lv_objects ) on listview_rollout close do callbacks.removeScripts #selectionSetChanged id:#SceneListView
タイトルバーの右上隅の[X]ボタンを押す、または MacroScript を再び呼び出して、ダイアログ ボックスを閉じるときには、選択セットの変更に合わせて表示を更新するために登録するコールバックを削除します。そうしないと、シーン内のオブジェクトを選択したときにコールバックがすでに閉じたロールアウトにアクセスを試みてしまい、エラーが発生することになります。
) try(destroyDialog listview_rollout)catch() createDialoglistview_rollout 500 200 callbacks.addScript #selectionSetChanged "listview_rollout.fillInSpreadSheet listview_rollout.lv_objects" id:#SceneListView
最後に、ユーザがシーン内の選択セットを変更した場合に Listview を更新するコールバックを登録します。
callbacks.addScript は、新しいコールバックを登録することを MAXScript に通知します。
#selectionSetChanged は、選択セットに変更があった場合に 3ds Max がブロードキャストする通知メッセージの名前です。
この文字列にはコールバックが起動したときに実際に実行されるスクリプトが含まれており、グローバルになったロールアウト定義のプロパティとして Listview にアクセスし、先に定義した fillInSpreadSheet 関数を呼び出します。
id:#SceneListView はこの特別なコールバック(たとえば上記の callbacks.removeScripts の呼び出し)だけに影響を与えることのできるユーザ定義の名前です。他の開発者が定義したコールバックや 3ds Max の出荷版には影響しません。
スクリプトを評価すると、チュートリアルの第 1 部で定義した[HowTo]カテゴリの SceneListView ActionItem が更新されます。
SceneListView スクリプトに対応するボタンを押すか、メニュー項目を選択するか、キーボード ショートカットを押すと、Listview ActiveX コントロールのダイアログ ボックスが表示されます。選択されたオブジェクトがない場合、リストは空になります。
オブジェクトをいくつか選択し、リストが自動的に更新される様子を確認してみます。選択セットを再び変更すると、リストはダイナミックに更新されます。オブジェクトを選択してから右クリックして[プロパティ](Properties)を選択し、[レンダリング可能](Renderable)チェックボックスのチェックマークを外します。Listview のチェックボックスのチェックマークも外されることに注意してください。
次に行うべき手順は、Listview 内のチェックボックスを .Renderable プロパティに双方向的にリンクするためのイベント ハンドラを追加し、Listview での変更がノード プロパティにも反映されるようにすることです。