はじめてのBlenderアドオン開発
Last Update: 2023.3.1
Blender 2.7
はじめてのBlenderアドオン開発
Blender 2.7
Last Update: 2023.3.1
2-10. BlenderのUIを制御する③
2-8節 から続けてきたBlenderのUI制御の解説ですが、本節ではその締めくくりとしてBlenderが提供する特殊なUIをアドオンから呼び出す方法について説明します。 本節では、ファイルブラウザなどの利用頻度の高いUIから検索ボックスなどのあまり使われないUIまで一通り説明します。
1-5節 を参考にして以下のソースコードを入力し、ファイル名を sample_2_10.py
として保存してください。
import bpy
from bpy.props import IntProperty, FloatProperty, EnumProperty
from bpy.props import FloatVectorProperty, StringProperty
bl_info = {
"name": "サンプル2-10: BlenderのUIを制御するアドオン3",
"author": "Nutti",
"version": (2, 0),
"blender": (2, 75, 0),
"location": "3Dビュー > ツールシェルフ",
"description": "BlenderのUIを制御するアドオン",
"warning": "",
"support": "TESTING",
"wiki_url": "",
"tracker_url": "",
"category": "User Interface"
}
class ShowPopupMessage(bpy.types.Operator):
bl_idname = "object.show_popup_message"
bl_label = "ポップアップメッセージ"
bl_description = "ポップアップメッセージ"
bl_options = {'REGISTER', 'UNDO'}
# execute() メソッドがないと、やり直し未対応の文字が出力される
def execute(self, context):
return {'FINISHED'}
def invoke(self, context, event):
wm = context.window_manager
# ポップアップメッセージ表示
return wm.invoke_popup(self, width=200, height=100)
# ポップアップメッセージに表示する内容
def draw(self, context):
layout = self.layout
layout.label("メッセージ")
class ShowDialogMenu(bpy.types.Operator):
bl_idname = "object.show_dialog_menu"
bl_label = "ダイアログメニュー"
bl_description = "ダイアログメニュー"
bl_options = {'REGISTER', 'UNDO'}
prop_int = IntProperty(
name="ダイアログプロパティ 1",
description="ダイアログプロパティ 1",
default=100,
min=0,
max=255
)
prop_float = FloatProperty(
name="ダイアログプロパティ 2",
description="ダイアログプロパティ 2",
default=0.75,
min=0.0,
max=1.0
)
prop_enum = EnumProperty(
name="ダイアログプロパティ 3",
description="ダイアログプロパティ 3",
items=[
('ITEM_1', "項目 1", "項目 1"),
('ITEM_2', "項目 2", "項目 2"),
('ITEM_3', "項目 3", "項目 3")
],
default='ITEM_1'
)
prop_floatv = FloatVectorProperty(
name="ダイアログプロパティ 4",
description="ダイアログプロパティ 4",
subtype='COLOR_GAMMA',
default=(1.0, 1.0, 1.0),
min=0.0,
max=1.0
)
def execute(self, context):
self.report(
{'INFO'},
"サンプル2-10: [1] %d, [2] %f, [3] %s, [4] (%f, %f, %f)"
% (self.prop_int, self.prop_float, self.prop_enum,
self.prop_floatv[0], self.prop_floatv[1],
self.prop_floatv[2])
)
return {'FINISHED'}
def invoke(self, context, event):
scene = context.scene
wm = context.window_manager
self.prop_int = scene.cm_prop_int
self.prop_float = scene.cm_prop_float
self.prop_enum = scene.cm_prop_enum
self.prop_floatv = scene.cm_prop_floatv
# ダイアログメニュー呼び出し
return wm.invoke_props_dialog(self)
class ShowFileBrowser(bpy.types.Operator):
bl_idname = "object.show_file_browser"
bl_label = "ファイルブラウザ"
bl_description = "ファイルブラウザ"
bl_options = {'REGISTER', 'UNDO'}
filepath = StringProperty(subtype="FILE_PATH")
filename = StringProperty()
directory = StringProperty(subtype="FILE_PATH")
def execute(self, context):
self.report(
{'INFO'},
"サンプル2-10: [FilePath] %s, [FileName] %s, [Directory] %s"
% (self.filepath, self.filename, self.directory)
)
return {'FINISHED'}
def invoke(self, context, event):
wm = context.window_manager
# ファイルブラウザ表示
wm.fileselect_add(self)
return {'RUNNING_MODAL'}
class ShowConfirmPopup(bpy.types.Operator):
bl_idname = "object.show_confirm_popup"
bl_label = "確認ポップアップ"
bl_description = "確認ポップアップ"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
self.report({'INFO'}, "サンプル2-10: 確認ポップアップボタンをクリックしました")
return {'FINISHED'}
def invoke(self, context, event):
wm = context.window_manager
# 確認メッセージ表示
return wm.invoke_confirm(self, event)
class ShowPropertyPopup(bpy.types.Operator):
bl_idname = "object.show_property_popup"
bl_label = "プロパティ付きポップアップ"
bl_description = "プロパティ付きポップアップ"
bl_options = {'REGISTER', 'UNDO'}
prop_int = IntProperty(
name="プロパティ 1",
description="プロパティ 1",
default=100,
min=0,
max=255
)
prop_float = FloatProperty(
name="プロパティ 2",
description="プロパティ 2",
default=0.75,
min=0.0,
max=1.0
)
prop_enum = EnumProperty(
name="プロパティ 3",
description="プロパティ 3",
items=[
('ITEM_1', "項目 1", "項目 1"),
('ITEM_2', "項目 2", "項目 2"),
('ITEM_3', "項目 3", "項目 3")
],
default='ITEM_1'
)
prop_floatv = FloatVectorProperty(
name="プロパティ 4",
description="プロパティ 4",
subtype='COLOR_GAMMA',
default=(1.0, 1.0, 1.0),
min=0.0,
max=1.0
)
def execute(self, context):
self.report(
{'INFO'},
"サンプル2-10: [1] %d, [2] %f, [3] %s, [4] (%f, %f, %f)"
% (self.prop_int, self.prop_float, self.prop_enum,
self.prop_floatv[0], self.prop_floatv[1],
self.prop_floatv[2])
)
return {'FINISHED'}
def invoke(self, context, event):
wm = context.window_manager
# プロパティ付きポップアップ表示
return wm.invoke_props_popup(self, event)
class ShowSearchPopup(bpy.types.Operator):
bl_idname = "object.show_search_popup"
bl_label = "検索ウィンドウ付きポップアップ"
bl_description = "検索ウィンドウ付きポップアップ"
bl_options = {'REGISTER', 'UNDO'}
bl_property = "item"
item = EnumProperty(
name="配置位置",
description="複製したオブジェクトの配置位置",
items=[
('ITEM_1', '項目1', '項目1'),
('ITEM_2', '項目2', '項目2'),
('ITEM_3', '項目3', '項目3')
],
default='ITEM_1'
)
def execute(self, context):
self.report({'INFO'}, "サンプル2-10: %s を選択しました" % self.item)
return {'FINISHED'}
def invoke(self, context, event):
wm = context.window_manager
# 検索ウィンドウ付きポップアップ表示
wm.invoke_search_popup(self)
# {'FINISHED'} を返す必要がある
return {'FINISHED'}
# ツールシェルフに「カスタムメニュー」タブを追加
class VIEW3D_PT_CustomMenu(bpy.types.Panel):
bl_label = "カスタムメニュー" # タブに表示される文字列
bl_space_type = 'VIEW_3D' # メニューを表示するエリア
bl_region_type = 'TOOLS' # メニューを表示するリージョン
bl_category = "カスタムメニュー" # タブを開いたメニューのヘッダーに表示される文字列
bl_context = "objectmode" # パネルを表示するコンテキスト
# 本クラスの処理が実行可能かを判定する
@classmethod
def poll(cls, context):
# オブジェクトが選択されている時のみメニューを表示させる
for o in bpy.data.objects:
if o.select:
return True
return False
# ヘッダーのカスタマイズ
def draw_header(self, context):
layout = self.layout
layout.label(text="", icon='PLUGIN')
# メニューの描画処理
def draw(self, context):
layout = self.layout
# ポップアップメッセージを表示する
layout.label(text="ポップアップメッセージを表示する:")
layout.operator(ShowPopupMessage.bl_idname)
layout.separator()
# ダイアログメニューを表示する
layout.label(text="ダイアログメニューを表示する:")
layout.operator(ShowDialogMenu.bl_idname)
layout.separator()
# ファイルブラウザを表示する
layout.label(text="ファイルブラウザを表示する:")
layout.operator(ShowFileBrowser.bl_idname)
layout.separator()
# 確認ポップアップを表示する
layout.label(text="確認ポップアップを表示する:")
layout.operator(ShowConfirmPopup.bl_idname)
layout.separator()
# プロパティ付きポップアップを表示する
layout.label(text="プロパティ付きポップアップを表示する:")
layout.operator(ShowPropertyPopup.bl_idname)
layout.separator()
# 検索ポップアップを表示する
layout.label(text="検索ポップアップを表示する:")
layout.operator(ShowSearchPopup.bl_idname)
# プロパティの初期化
def init_props():
scene = bpy.types.Scene
scene.cm_prop_int = IntProperty(
name="Prop 1",
description="Integer Property",
default=100,
min=0,
max=255
)
scene.cm_prop_float = FloatProperty(
name="Prop 2",
description="Float Property",
default=0.75,
min=0.0,
max=1.0
)
scene.cm_prop_enum = EnumProperty(
name="Prop 3",
description="Enum Property",
items=[
('ITEM_1', "項目 1", "項目 1"),
('ITEM_2', "項目 2", "項目 2"),
('ITEM_3', "項目 3", "項目 3")
],
default='ITEM_1'
)
scene.cm_prop_floatv = FloatVectorProperty(
name="Prop 4",
description="Float Vector Property",
subtype='COLOR_GAMMA',
default=(1.0, 1.0, 1.0),
min=0.0,
max=1.0
)
# プロパティを削除
def clear_props():
scene = bpy.types.Scene
del scene.cm_prop_int
del scene.cm_prop_float
del scene.cm_prop_enum
del scene.cm_prop_floatv
def register():
bpy.utils.register_module(__name__)
init_props()
print("サンプル2-10: アドオン「サンプル2-10」が有効化されました。")
def unregister():
bpy.utils.unregister_module(__name__)
clear_props()
print("サンプル2-10: アドオン「サンプル2-10」が無効化されました。")
if __name__ == "__main__":
register()
1-5節 を参考に作成したアドオンを有効化すると、コンソールウィンドウに以下の文字列が出力されます。
サンプル2-10: アドオン「サンプル2-10」が有効化されました。
そして、[3Dビュー] エリアのツール・シェルフにタブ [カスタムメニュー] が追加されます。
[3Dビュー] エリアのツール・シェルフのタブ [カスタムメニュー] をクリックすると、カスタムメニューのメニューが表示されます。
[カスタムメニュー] タブに設置されたボタンをクリックし、動作を確認します。
[ポップアップメッセージ] ボタンを押すと、ポップアップメッセージが表示されます。
1 | タブ [カスタムメニュー] の [ポップアップメッセージ] ボタンをクリックします。 |
2 | クリックした場所にポップメッセージが表示されます。 |
[ダイアログメニュー] ボタンを押すと、4つのプロパティと [OK] ボタン付きのダイアログメニューが表示されます。
1 | タブ [カスタムメニュー] の [ダイアログメニュー] ボタンをクリックします。 |
2 | クリックした場所にダイアログメニューが開きます。 |
3 | ダイアログメニュー上のプロパティは変更することができます。 |
4 | [OK] ボタンを押すとスクリプト実行ログに以下のメッセージが表示されます。サンプル2-10: [1] (ダイアログプロパティ 1の値), [2] (ダイアログプロパティ 2の値), [3] (ダイアログプロパティ 3の識別子), [4] (ダイアログプロパティ 4の値) |
[ファイルブラウザ] ボタンを押すと、ファイルブラウザが表示されます。
1 | タブ [カスタムメニュー] の [ファイルブラウザ] ボタンをクリックします。 |
2 | ファイルブラウザが開きます。 |
3 | 適当にファイルを開くと、スクリプト実行ログに以下のメッセージが表示されます。サンプル2-10: [FilePath] (開いたファイルのファイルパス), [FileName] (開いたファイルのファイル名), [Directory] (開いたファイルが置かれたディレクトリ) |
[確認ポップアップ] ボタンを押すと、操作を実行するか中断するかを問うポップアップが表示されます。
1 | タブ [カスタムメニュー] の [確認ポップアップ] ボタンをクリックします。 |
2 | 操作を実行するか中断するかを問うポップアップが表示されるので、[確認ポップアップ] をクリックします。 |
3 | スクリプト実行ログに以下のメッセージが表示されます。仮に、[確認ポップアップ] をクリックしなかった場合は、処理が中断されます。サンプル2-10: 確認ポップアップボタンをクリックしました |
[プロパティ付きポップアップ] ボタンを押すと、4つのプロパティがポップアップで表示されます。
1 | タブ [カスタムメニュー] の [プロパティ付きポップアップ] ボタンをクリックします。 |
2 | プロパティを変更するたびに、[スクリプト実行ログ] に以下のメッセージが表示されます。サンプル2-10: [1] (プロパティ 1の値), [2] (プロパティ 2の値), [3] (プロパティ 3の識別子), [4] (プロパティ 4の値) |
[検索ウィンドウ付きポップアップ] ボタンを押すと、検索ウィンドウがポップアップで表示されます。
1 | タブ [カスタムメニュー] の [検索ウィンドウ付きポップアップ] ボタンをクリックします。 |
2 | 検索ウィンドウ付きポップアップが表示されます。 |
3 | [項目1]・[項目2]・[項目3]の中から検索することができます。 |
4 | 項目を確定するとスクリプト実行ログに以下のメッセージが表示されます。サンプル2-10: (確定した項目の識別子) を選択しました |
1-5節 を参考に有効化したアドオンを無効化すると、コンソールウィンドウに以下の文字列が出力されます。
サンプル2-10: アドオン「サンプル2-10」が無効化されました。
ポップアップメッセージを表示する方法について説明します。
ポップアップメッセージを表示するためのオペレータクラスを、以下に示します。
class ShowPopupMessage(bpy.types.Operator):
bl_idname = "object.show_popup_message"
bl_label = "ポップアップメッセージ"
bl_description = "ポップアップメッセージ"
bl_options = {'REGISTER', 'UNDO'}
# execute() メソッドがないと、やり直し未対応の文字が出力される
def execute(self, context):
return {'FINISHED'}
def invoke(self, context, event):
wm = context.window_manager
# ポップアップメッセージ表示
return wm.invoke_popup(self, width=200, height=100)
# ポップアップメッセージに表示する内容
def draw(self, context):
layout = self.layout
layout.label("メッセージ")
ポップアップメッセージの表示はボタンを押したときに呼ばれる invoke
メソッドで行っています。
invoke
メソッドは、処理が実行された時に呼ばれるメソッドです。 execute
メソッドも処理が実行された時に呼ばれますが、execute
メソッドの引数にはなかったイベント event
を受け取る点が異なります。 3-1節 でも説明しますが、引数 event
には invoke
メソッドが呼ばれた時のマウスの位置や発生したキーイベントなどの情報が含まれています。 また、invoke
と execute
が2つ定義されていた場合、メニューの項目を選択した時やボタンを押したなどのUIから操作を行うと invoke
が優先的に呼ばれます。 一方、2-2節 で説明した bpy.ops.<オペレーションクラスのbl_idname>
を実行すると execute
が呼び出されます。
このようにユーザからの入力を積極的に使いたい場合や、invoke
メソッドで前処理を行った後に bpy.ops.<オペレーションクラスのbl_idname>
を実行じて excute
を呼び出したい場合に invoke
メソッドを利用します。
本節のサンプルでは、invoke
メソッド内で wm.invoke_popup
関数を次に示す引数を指定して実行しています。
引数 | 型 |
---|---|
第1引数 | オペレータクラス |
width |
整数 |
height |
整数 |
wm.invoke_popup
関数により表示されるポップアップのUIは、draw
メソッドで定義します。 本節のサンプルでは、メッセージ
と書かれたラベルを表示しています。
wm.invoke_popup
関数の戻り値は {'RUNNING_MODAL'}
ですが、本節では説明を省略します。 ポップアップメッセージを表示する時には、wm.invoke_popup
関数を invoke
メソッドの戻り値に指定すればよいということだけを覚えておきましょう。
[ポップアップメッセージ] ボタンを配置する処理を以下に示します。
# ポップアップメッセージを表示する
layout.label(text="ポップアップメッセージを表示する:")
layout.operator(ShowPopupMessage.bl_idname)
ポップアップメッセージの応用として、ポップアップからプロパティを入力できるダイアログメニューを表示することもできます。 ダイアログメニューを表示するためには、context.window_manager.invoke_props_dialog
関数を使用します。
ダイアログメニューを表示するオペレータクラスを以下に示します。
class ShowDialogMenu(bpy.types.Operator):
bl_idname = "object.show_dialog_menu"
bl_label = "ダイアログメニュー"
bl_description = "ダイアログメニュー"
bl_options = {'REGISTER', 'UNDO'}
prop_int = IntProperty(
name="ダイアログプロパティ 1",
description="ダイアログプロパティ 1",
default=100,
min=0,
max=255
)
prop_float = FloatProperty(
name="ダイアログプロパティ 2",
description="ダイアログプロパティ 2",
default=0.75,
min=0.0,
max=1.0
)
prop_enum = EnumProperty(
name="ダイアログプロパティ 3",
description="ダイアログプロパティ 3",
items=[
('ITEM_1', "項目 1", "項目 1"),
('ITEM_2', "項目 2", "項目 2"),
('ITEM_3', "項目 3", "項目 3")
],
default='ITEM_1'
)
prop_floatv = FloatVectorProperty(
name="ダイアログプロパティ 4",
description="ダイアログプロパティ 4",
subtype='COLOR_GAMMA',
default=(1.0, 1.0, 1.0),
min=0.0,
max=1.0
)
def execute(self, context):
self.report(
{'INFO'},
"サンプル2-10: [1] %d, [2] %f, [3] %s, [4] (%f, %f, %f)"
% (self.prop_int, self.prop_float, self.prop_enum,
self.prop_floatv[0], self.prop_floatv[1],
self.prop_floatv[2])
)
return {'FINISHED'}
def invoke(self, context, event):
scene = context.scene
wm = context.window_manager
self.prop_int = scene.cm_prop_int
self.prop_float = scene.cm_prop_float
self.prop_enum = scene.cm_prop_enum
self.prop_floatv = scene.cm_prop_floatv
# ダイアログメニュー呼び出し
return wm.invoke_props_dialog(self)
ShowDialogMenu
クラスには4つのプロパティクラスの変数が宣言されていて、ダイアログメニューではこれらのプロパティを表示します。 ダイアログメニューの表示は wm.invoke_props_dialog
関数で行います。 引数には、ダイアログメニューに表示するプロパティクラスの変数を持つオペレータクラスのインスタンスを渡します。
wm.invoke_props_dialog
関数の引数を以下に示します。
引数 | 型 |
---|---|
第1引数 | オペレータクラスのインスタンス |
width |
整数 |
height |
整数 |
wm.invoke_props_dialog
関数の戻り値は、ポップアップメッセージと同様に {'RUNNING_MODAL'}
ですが、本節では説明を省略します。 ダイアログメニューを表示する時には、wm.invoke_props_dialog
関数を invoke
メソッドの戻り値に指定すればよいということだけを覚えておきましょう。
ダイアログメニューに表示された [OK] ボタンを押すと、execute
メソッドが実行されます。 execute
メソッドでは、ダイアログメニューのプロパティに指定した値をスクリプト実行ログに出力します。 ダイアログメニューで指定したプロパティの値でアドオンの処理を実行したいときに活用しましょう。
[ダイアログメニュー] ボタンを配置する処理を以下に示します。
# ダイアログメニューを表示する
layout.label(text="ダイアログメニューを表示する:")
layout.operator(ShowDialogMenu.bl_idname)
ファイルを開いたり保存したりする時など、Blender標準の機能を使用した場合でも、ファイルを選択するためのファイルブラウザを表示する機能が存在します。 アドオンからファイルブラウザを表示するためには、context.window_manager.fileselect_add
関数を利用します。
本節のサンプルでは、以下のコードでファイルブラウザを表示しています。
class ShowFileBrowser(bpy.types.Operator):
bl_idname = "object.show_file_browser"
bl_label = "ファイルブラウザ"
bl_description = "ファイルブラウザ"
bl_options = {'REGISTER', 'UNDO'}
filepath = StringProperty(subtype="FILE_PATH")
filename = StringProperty()
directory = StringProperty(subtype="FILE_PATH")
def execute(self, context):
self.report(
{'INFO'},
"サンプル2-10: [FilePath] %s, [FileName] %s, [Directory] %s"
% (self.filepath, self.filename, self.directory)
)
return {'FINISHED'}
def invoke(self, context, event):
wm = context.window_manager
# ファイルブラウザ表示
wm.fileselect_add(self)
return {'RUNNING_MODAL'}
ファイルブラウザを表示するためには、invoke
メソッド内で wm.fileselect_add
関数を呼ぶ必要があります。 引数には、ファイルブラウザ内でファイルを確定した時に実行される execute
メソッドが定義されたオペレータクラスのインスタンスを指定します。 invoke
メソッドの戻り値は、{'RUNNING_MODAL'}
にする必要があります。
ファイルブラウザで確定したファイルの情報を保存するために、クラス変数 filepath
, filename
, directory
を宣言しています。 ファイルブラウザからファイルの情報を受け取るためには、本節のサンプルと同じ変数名にする 必要があることに注意が必要です。 なお、filepath
や directory
は、プロパティクラス StringProperty
の引数 subtype
にファイルパスを格納するプロパティであることを示す FILE_PATH
を指定する必要があります。
ファイルブラウザでファイルを確定すると execute
メソッドが呼ばれ、確定したファイルパス・ファイル名・ファイルが置かれたディレクトリをスクリプト実行ログに表示します。
最後に、[ファイルブラウザ] ボタンを配置する処理を以下に示します。
# ファイルブラウザを表示する
layout.label(text="ファイルブラウザを表示する:")
layout.operator(ShowFileBrowser.bl_idname)
Blenderの機能の中には、実行する前に処理を実行するか中断するかを確認するためのポップアップを表示する機能があります。 例えば、[情報] エリアのメニュー [ファイル] > [スタートアップファイルを保存] は、実行確認のポップアップを表示する例の1つです。
実行確認のポップアップは、context.window_manager.invoke_confirm
関数により表示することができます。
本節のサンプルでは、以下のコードで実行確認のポップアップを表示しています。
class ShowConfirmPopup(bpy.types.Operator):
bl_idname = "object.show_confirm_popup"
bl_label = "確認ポップアップ"
bl_description = "確認ポップアップ"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
self.report({'INFO'}, "サンプル2-10: 確認ポップアップボタンをクリックしました")
return {'FINISHED'}
def invoke(self, context, event):
wm = context.window_manager
# 確認メッセージ表示
return wm.invoke_confirm(self, event)
実行確認のポップアップは、invoke
メソッド内から wm.invoke_confirm
関数を呼び出して表示しています。
vm.invoke_confirm
関数の引数を以下に示します。
引数 | 意味 |
---|---|
第1引数 | 実行確認ポップアップにて処理の実行を決定したときに呼び出される execute メソッドが定義されたオペレータクラスのインスタンス |
第2引数 | invoke メソッドの引数 event を指定 |
[確認ポップアップ] ボタンを配置する処理を以下に示します。
# 確認ポップアップを表示する
layout.label(text="確認ポップアップを表示する:")
layout.operator(ShowConfirmPopup.bl_idname)
値を変更することができる、プロパティ付きポップアップを作ることもできます。 実行結果を見るとダイアログメニューと同じ動きに見えますが、ダイアログメニューは [OK] ボタンを押すまで処理が実行されないのに対し、プロパティ付きポップアップではプロパティを変更するたびに処理が実行されます。
本節のサンプルでは、以下のようにしてプロパティ付きポップアップを表示しています。
class ShowPropertyPopup(bpy.types.Operator):
bl_idname = "object.show_property_popup"
bl_label = "プロパティ付きポップアップ"
bl_description = "プロパティ付きポップアップ"
bl_options = {'REGISTER', 'UNDO'}
prop_int = IntProperty(
name="プロパティ 1",
description="プロパティ 1",
default=100,
min=0,
max=255
)
prop_float = FloatProperty(
name="プロパティ 2",
description="プロパティ 2",
default=0.75,
min=0.0,
max=1.0
)
prop_enum = EnumProperty(
name="プロパティ 3",
description="プロパティ 3",
items=[
('ITEM_1', "項目 1", "項目 1"),
('ITEM_2', "項目 2", "項目 2"),
('ITEM_3', "項目 3", "項目 3")
],
default='ITEM_1'
)
prop_floatv = FloatVectorProperty(
name="プロパティ 4",
description="プロパティ 4",
subtype='COLOR_GAMMA',
default=(1.0, 1.0, 1.0),
min=0.0,
max=1.0
)
def execute(self, context):
self.report(
{'INFO'},
"サンプル2-10: [1] %d, [2] %f, [3] %s, [4] (%f, %f, %f)"
% (self.prop_int, self.prop_float, self.prop_enum,
self.prop_floatv[0], self.prop_floatv[1],
self.prop_floatv[2])
)
return {'FINISHED'}
def invoke(self, context, event):
wm = context.window_manager
# プロパティ付きポップアップ表示
return wm.invoke_props_popup(self, event)
プロパティ付きポップアップは、invoke
メソッド内から context.window_manager.invoke_props_popup
関数を実行することで表示することができます。 プロパティを変更すると execute
メソッドが実行され、 現在のプロパティの値がスクリプト実行ログに表示されます。
wm.invoke_props_popup
関数には、以下に示す引数を指定します。
引数 | 意味 |
---|---|
第1引数 | プロパティを変えた時に呼び出される execute メソッドが定義されたオペレータクラスのインスタンス |
第2引数 | invoke メソッドの引数 event を指定 |
なお、プロパティ付きポップアップで表示されたプロパティは、ツール・シェルフのオプションにも表示されているため、ポップアップが閉じてしまった場合でも他の操作を行わなわない限り変更することができます。
[プロパティ付きポップアップ] ボタンを配置する処理を以下に示します。
# プロパティ付きポップアップを表示する
layout.label(text="プロパティ付きポップアップを表示する:")
layout.operator(ShowPropertyPopup.bl_idname)
あらかじめ登録した項目の中から検索することができる、検索ウィンドウ付きのポップアップを表示することができます。 実際このUIがどのように役立つのか、筆者もよくわかっていませんが、BlenderのAPIとして用意されているので紹介します。
本節のサンプルでは、検索ウィンドウ付きポップアップを以下のコードにより表示します。
class ShowSearchPopup(bpy.types.Operator):
bl_idname = "object.show_search_popup"
bl_label = "検索ウィンドウ付きポップアップ"
bl_description = "検索ウィンドウ付きポップアップ"
bl_options = {'REGISTER', 'UNDO'}
bl_property = "item"
item = EnumProperty(
name="配置位置",
description="複製したオブジェクトの配置位置",
items=[
('ITEM_1', '項目1', '項目1'),
('ITEM_2', '項目2', '項目2'),
('ITEM_3', '項目3', '項目3')
],
default='ITEM_1'
)
def execute(self, context):
self.report({'INFO'}, "サンプル2-10: %s を選択しました" % self.item)
return {'FINISHED'}
def invoke(self, context, event):
wm = context.window_manager
# 検索ウィンドウ付きポップアップ表示
wm.invoke_search_popup(self)
# {'FINISHED'} を返す必要がある
return {'FINISHED'}
検索ウィンドウ付きのポップアップを表示するためには、invoke
メソッド内で context.window_manager.invoke_search_popup
関数を使います。 引数には、項目確定時に呼び出される execute
メソッドが定義されたクラスのインスタンスを指定します。 なお invoke
メソッドは {'FINISHED'}
を返す必要があります。
項目を確定すると execute
メソッドが呼び出され、選択した項目の識別子がスクリプト実行ログに表示されます。
検索ウィンドウで検索できる項目は、アドオン開発者が追加する 必要があります。 検索ウィンドウへ追加する項目リストを持つ変数は EnumProperty
クラスの型で定義する必要があり、クラス変数 bl_property
に定義した変数名を代入する必要があります。 本節のサンプルではクラス変数 item
が項目リストであるため、bl_property="item"
とします。
最後に、[検索ウィンドウ付きポップアップ] ボタンを配置する処理を以下に示します。
# 検索ポップアップを表示する
layout.label(text="検索ポップアップを表示する:")
layout.operator(ShowSearchPopup.bl_idname)
本節では、Blenderが提供するUIをアドオンから呼び出す方法について説明しました。
2-9節 に引き続き本節のサンプルでも様々なAPIが登場しましたので、本節で紹介したUI関連のAPIをまとめておきます。
UI | API |
---|---|
ポップアップメッセージ | context.window_manager.invoke_popup |
ダイアログメニュー | context.window_manager.invoke_props_dialog |
ファイルブラウザ | context.window_manager.fileselect_add |
確認ポップアップ | context.window_manager.invoke_confirm |
プロパティ付きポップアップ | context.window_manager.invoke_props_popup |
検索ウィンドウ付きポップアップ | context.window_manager.invoke_search_popup |
2-8節 から本節まで3節にわたりBlenderのUIを構築する方法を説明しましたが、わかりやすいUIを構築するためのポイントについては説明していません。 わかりやすいUIを構築するのはアドオンの開発とは異なり、明確な答えがありません。 他の方が開発されたアドオンのUIを参考にするだけでなく、世の中に公開されているWebページやアプリの画面などにもアンテナを常に張り巡らせ、自分で良いと思ったデザインを真似して吸収していく ことが、わかりやすいUIを構築するための早道であると思います。
本節で前編は終わりです。 ここまで読まれた方であれば、アドオンを作るだけでなくPythonで書かれているBlenderのUIも自由に変更することができるようになっていることでしょう。 後編では、より高度なアドオンを作りたい人向けの話題を取り上げます。
window_manager
を通して呼び出すことができるinvoke
メソッドと execute
メソッドは、引数にイベント情報を受け取らない点で異なるinvoke
メソッドが優先的に実行されるbpy.ops.<オペレーションクラスのbl_idname>
オペレータクラスの処理を実行した場合は、execute
メソッドが優先的に実行される