状況によって数や内容が変わるもの1つ1つに対して別々のメニューを付けるのは、単純な方法ではできない。
例では、リストで並べたマテリアル1つ1つに、メニューを開閉できる切り替えボタンを作る。
All Material List ver2.2.0にて、「マテリアル割り当て済みオブジェクトをリスト表示する機能」を開発した時の仕組みを紹介する。
もくじ
作り方
CollectionPropertyを使って実装する。
ここにアイテムを保存し、ここにアイテムがあるかどうかを判定し、あるならばメニューを表示する、という仕組みを作る。
主に作るものは下記の3つ。
- CollectionProperty
- 開閉用オペレーターのメニュー ( ▼ ボタン)
- 開閉用オペレーター
仕組み
CollectionProperty
class SAVEMS_PR_asobj_colle(bpy.types.PropertyGroup): mat : PointerProperty(name="mat",type=bpy.types.Material) name : StringProperty(name="name") # 登録 bpy.types.Scene.am_list_asobj_colle = CollectionProperty(type=SAVEMS_PR_asobj_colle) # 登録解除 del bpy.types.Scene.am_list_asobj_colle
CollectionPropertyは、各アイテムに複数の情報を保存できるリストのようなもの。サンプルでは各シーンに保存される(bpy.types.Sceneを変えれば別のデータにも保持できる)。
ここに名前とマテリアルを保存する。
Pointerroperty ならオブジェクトやマテリアルなどを格納することができる。
各アイテムに開閉オペレーターを用意
op = rowobj.operator("am_list.mat_asobj_toggle",icon=obj_icon) op.item=item.name # アイテム名をオペレーターに受け渡す
- for文の中に開閉ボタンを置けば、各アイテムをオペレーターに渡すことができる
- アイテム名をオペレーターに受け渡す
開閉オペレーターを実行する
item_mat = bpy.data.materials[self.item] colle = bpy.context.scene.am_list_asobj_colle # メニューから受け取ったアイテムが、CollectionProperty内にすでにあるかを判定する obj_on = True for l in colle: if l.mat == item_mat: obj_on = False # ある場合は、CollectionPropertyからアイテムを除去する if obj_on: item = colle.add() item.name = self.item item.mat = item_mat # ない場合は、CollectionPropertyに名前とアイテムそのものを追加する else: index=colle.find(self.item) colle.remove(index)
- このオペレーターは、CollectionPropertyにアイテムを追加・削除するもの
- メニューから受け取ったアイテムが、CollectionProperty内にすでにあるかを判定する
- for文で探す
- ある場合は、CollectionPropertyからアイテムを除去する
- ない場合は、CollectionPropertyに名前とアイテムそのものを追加する
メニュー表示
- for文でアイテムがCollectionProperty内にすでにあるかを判定する
- ある場合は、格納されたメニューを表示する
- メニューの開閉アイコンも同様に判定して、あるなら ▼ 、ないなら ▶ に変更する
バグ回避
- 何らかの動作によってCollectionPropertyのアイテムが残り続けてしまうことを回避する
- 全て開く・全て閉じるオペレーターを用意する
- 実際の処理は、全アイテムをCollectionPropertyに追加・削除になる