アドオンで使うメニューの作り方を紹介する。
アドオン開発で得た知識をここにまとめる。
もくじ
ダウンロード
この記事では、上記の学習用に作ったアドオンを元に解説する。
- アドオン内のメニューの場所
- 3Dビュー → サイドバー(Nキー) → Tools → Layout Practice
さまざまなレイアウトの要素表
UILayout(bpy_struct) — Blender Python API
上記のUILayoutのAPIからすべてを見ることができるが、よく使うものは限られている。
この記事では主に、下記の表にある要素を紹介する。
基本的なレイアウト要素
レイアウト | 説明 |
---|---|
label | テキスト layout.label(text="hoge",icon="ADD") |
separator | 空白 layout.separator() |
row | 横並びにする row = layout.row(align=True) |
col | 縦表示にする col = layout.column(align=True) |
box | 要素を囲う box = layout.box() |
split | 横に2つに分割する sp = layout.split(align=True,factor=0.9) |
operator | オペレーターのメニュー layout.operator("mesh.primitive_cube_add") |
prop | プロパティのメニュー layout.prop(bpy.context.objcet,"name") |
レイアウトのオプション
レイアウト | 説明 |
---|---|
scale_x / scale_y | 要素を大きさを変える layout.scale_x = 1.2 |
alignment | 左・中央・右に整列する layout.alignment = "LEFT" |
alert | 警告表示する layout.alert = True |
emboss | エンボスを消す layout.emboss= False |
active | 暗く表示させる layout.active = False |
enabled | 暗く表示させる(一切操作できなくさせる) layout.enabled= False |
基本のレイアウト
label テキスト
#des labelは、文字列 layout.label(text="label 文字列")
単純な文字列を表示する。
メニューのタイトルやユーザーに伝えたい内容を書ける。
メニューはあくまで機能にアクセスするためのものなので、長文の説明を書きたい場合は他の場所でやる(アドオンのドキュメントやOperatorのbl_description・ポップアップ表示など)。
separator 空白
layout.label(text="separator 空白") layout.separator()
単純な空白を作る。
メニュー要素の関係を分けたい時に使える。
factorオプションに数値を設定すれば大きな空白を作ることができる。
layout.separator(factor=3)
row 横並びにする
#des 横表示 row = layout.row(align=True) row.label(text="row 横表示にする") row.label(text="align=Trueで") row.label(text="隙間詰め")
要素を横並びにする。
基本的なレイアウト要素。
rowやcol、splitなどは、align=Trueで隙間を詰めることができる。
自分は基本的に入れて、隙間を開けたい時はseparatorを入れている。
col 縦並びにする
要素を縦並びにする。
align=Trueを使えば通常の縦並びより隙間を詰めることができるのが便利。
#des 縦表示 col = layout.column(align=True) col.label(text="col 縦表示にする") col.label(text="col 縦表示にする") col.label(text="col 縦表示にする")
box 要素を囲う
#des ボックス box = layout.box() box.label(text="囲うのはbox") box.label(text="要素をまとめたい時に便利")
要素をボックスで囲う。
要素をまとめたい時に便利。
box内では 上のcol の align=True は反映されないので注意。
オペレーターのメニュー
operator オペレーターのメニュー
layout.label(text="operator オペレーターのメニュー",icon="DOT") layout.operator("mesh.primitive_cube_add")
bpy.opsと()はいらないので注意。
textやiconで修飾できる
layout.label(text="textやiconで修飾できる",icon="DOT") layout.operator("mesh.primitive_cube_add",text="CUBE",icon="MESH_CUBE") layout.separator()
textで名前を設定できる。
これがない場合は、Operatorのbl_labelが表示される。
text=""のように値がないテキストを設定した場合は、アイコンのみが表示される。
iconでアイコンを設定できる。
使えるアイコンを調べるには、Blender内臓のicon viewerアドオンが便利。
オペレーターのプロパティは、末尾に~.〇〇のように書ける
layout.label(text="オペレーターのプロパティは、末尾に~.〇〇のように書ける",icon="DOT") layout.label(text="3Dカーソルの位置に依存せず常にワールドの中心に配置") layout.operator("mesh.primitive_cube_add",text="CUBE (location 0)",icon="MESH_CUBE").location=(0,0,0) layout.separator()
オペレーターのプロパティをあらかじめ決めておきたい場合は、下記のように書く。
メニューから実行されたときにプロパティの値を固定したい場合は、あらかじめこのように設定しておく必要がある。
Blenderのオペレーターは、プロパティが初期値のままならユーザーが事後設定メニューで切り替えた設定が優先されるため。
layout.operator("mesh.primitive_cube_add").location=(0,0,0)
代入することで複数のプロパティを書ける
layout.label(text="代入することで複数のプロパティを書ける",icon="DOT") layout.label(text="回転X45度を追加") op = layout.operator("mesh.primitive_cube_add",text="CUBE (location 0,rotation X45)",icon="MESH_CUBE") op.location=(0,0,0) op.rotation=(0.785,0,0) layout.separator()
複数のプロパティの値を設定したい場合はOperator自体を代入して書くとよい。
様々なレイアウト要素
基本的にrowやcolなどのサブ要素を作ってそこに設定する。
レイアウトのオプションは設定したレイアウト要素全てに適用されるので 、直接layoutに設定するとそれ以下のメニュー全てに反映されてしまう。
scale_x / scale_y 要素を大きさを変える
layout.label(text="scale_x / scale_y 要素を大きさを変える",icon="DOT") row = layout.row(align=True) row.scale_x = 3 row.scale_y = 3 row.operator("mesh.primitive_cube_add") layout.separator()
要素を大きくしたり小さくしたりする。
scale_xが横幅。
scale_yが縦幅。
メイン機能のオペレーターのボタンを少し大きめにすると、どれがメインボタンなのかわかりやすくてよい。
スカルプトやグリースペンシルなどのペンタブで扱うこと前提の機能の場合は、ボタンを大きくすると押しやすい。
split 分割する
layout.label(text="Split 分割する",icon="DOT") sp = layout.split(align=True,factor=0.7) sp.operator("mesh.primitive_cube_add") sp.operator("mesh.primitive_cube_add") layout.separator()
要素を分割する。
1行内に2つの要素を指定間隔で横並びしたいときに使える。
factorの値を0.0~1.0の間で指定する。
alignment 左・中央・右に整列する
layout.label(text="alignment 左・中央・右に整列する",icon="DOT") row = layout.row(align=True) row.alignment="LEFT" row.operator("mesh.primitive_cube_add") layout.separator()
メニューを整列する。
右端や左端に寄せたいときに使える。
LEFT, RIGHT, CENTER から選べる。
alert 警告表示する
layout.label(text="alert 警告表示する",icon="DOT") row = layout.row(align=True) row.alert=True row.operator("mesh.primitive_cube_add") layout.separator()
エンボスの色を赤に変える。
問題が発生していることを警告する時に使える。
テキストなら赤文字になる。
ちなみにBlenderのUIlayoutでは、メニューの色を細かく設定することはできない。
開発者が扱えるのはalertの赤と、propのboolなどが有効な時の青だけ。
emboss エンボスを消す
layout.label(text="emboss エンボスを消す",icon="DOT") row = layout.row(align=True) row.operator("mesh.primitive_cube_add",emboss=False) layout.separator()
operatorやpropのエンボスを消す。
あまり強調させたくない場合や、ボタンとしても押せるテキストを用意したい場合に使う。
labelにembossを付けることはできない。
active 暗く表示させる
layout.label(text="active ブラックアウトさせる",icon="DOT") row = layout.row(align=True) row.active = False row.operator("mesh.primitive_cube_add") layout.separator()
要素を暗く表示させる。
要素が使える状況ではないことをユーザーに知らせる事ができる。
enabled 暗く表示させる(一切操作できなくさせる)
layout.label(text="enabled ブラックアウトさせる(一切操作できなくさせる)",icon="DOT") row = layout.row(align=True) row.enabled = False row.operator("mesh.primitive_cube_add") layout.separator()
enabledは、activeのように暗く表示にさせる効果に加え、ボタンをクリックしても動作しなくなる。
絶対に動作させたくないときに使える。
自分はなんらかの想定外の時にも一切操作できなくなるのが好きではないので、あまり使っていない。
また、一切使えないのであれば単純に非表示にした方がメニューがすっきりして見やすくなる場合もある。
prop プロパティ
props = bpy.context.scene.bktemp box = layout.box() col = box.column() col.use_property_split = True #des プロパティエディターのようにメニューを分割表示する col.use_property_decorate = False #des キーフレームを打つアイコンを消す col.prop(props,"Bool",text="真偽") col.prop(props,"Int",text="整数") col.prop(props,"String",text="文字列") col.prop(props,"Float",text="小数点のある数値") col.prop(props,"FloatVector",text="複数の小数点のある数値") rows = col.row(align=True) rows.prop(props,"Enum",text="複数の文字列",expand=True) col.prop(props,"Pointer",text="オブジェクトなどのBlenderのデータを格納できるプロパティ")
プロパティを表示する。
上記では、bpy.context.scene.bktemp 以下にあるBoolやIntなどのプロパティを表示するメニュー。
col.use_property_split = Trueを付けると、textとメニューが分けられて見やすくなる。
このプロパティにもtext・icon・embossなどを付けることができる。
- enumのメニューを横並びにするには、rowとexpand=Trueが必要
- IntやFloatの数値量を見やすくしたい時は、slider=Trueを付ける
- ※ プロパティのminとmax(下限と上限)があらかじめ設定されている場合のみ
応用 - 開閉できるメニューを作る
ここまで掲載した要素を応用して、クリックしたらメニューが開き、ONの文字が表示されるメニューを作る。
開閉用メニューのプロパティの登録
- window_managerに、あらかじめ「ui_layout」というメニュー開閉用のBoolプロパティを登録しておく
class BKTEMP_WindowManager(PropertyGroup): ui_layout : BoolProperty(name="基本のレイアウト") classes = ( BKTEMP_WindowManager, ) def register(): for cls in classes: bpy.utils.register_class(cls) bpy.types.WindowManager.bktemp = PointerProperty(type=BKTEMP_WindowManager) def unregister(): for cls in reversed(classes): bpy.utils.unregister_class(cls) del bpy.types.WindowManager.bktemp
メニューを作成
wm = bpy.context.window_manager.bktemp row = layout.row(align = True) row.alignment = "LEFT" row.prop(wm, "ui_layout", icon="TRIA_DOWN" if wm.ui_layout else "TRIA_RIGHT", emboss=False) if wm.ui_layout: layout.label(text="ON",icon="NONE")
- rowで、要素をまとめる
- alignmentにより、プロパティの文字を左に寄せる
- propのデフォルトはCENTERなので、中央によってしまい、文字が読みづらいためこれを設定する
- row.prop(wm, "ui_layout")で開閉用プロパティメニューを作る
- iconを設定する
- アイコンにもif文を使うことができる
- プロパティが有効なら▼になる
- そうでないなら▶になる
- embossで、エンボスを消して、あまり主張しすぎないようにする
- if wm.ui_layout: のif文で、開閉用プロパティが有効ならメニューを表示するようにする
その他
EnumProperty
モディファイア追加メニューのように横並びにする
各列ごとのラベルは、下記のようにして他のアイテムと同じく並べると、選択できるアイテムにはならずにラベルにできる。
('', 'Modify', 'description', 'None', 0) , sp = layout.split() for keyname, label, desc, icon_val, num in tgt_mod_items: if keyname == "": col = sp.column(align=True) col.label(text=label,icon="NONE") continue op = col.operator("automirror.modifier_add", text=label, icon=icon_val) if act_obj.type == "GPENCIL": op.gp_mod_type = keyname else: op.mesh_mod_type = keyname
bpy.types.Menuのメニューは、splitで横並びのメニューにできる。
モディファイア追加メニューの作り方参考リンク
How to rebuild the Add Modifier Menu Layout? - Coding / Python Support - Blender Artists Community
複数選択できるEnumPropertyの作り方
FBXエクスポーターのオブジェクトタイプような、複数選択できるEnumPropertyの作り方。
通常のEnumでは単一のStringしか選択できないが、
options={"ENUM_FLAG"}を付けることで複数項目を設定できるPropertyにすることができる。
数字を右揃えにする
数字を普通に縦列表示すると左揃えされるので、桁数が多い数字の比較が見にくい。 zfillでゼロ埋めする方法もあるが、 alignment="RIGHT" で右揃えにして、 ui_units_x で固定幅を設定すると、きれいに並べることができる。