Blender插件之操作器(Operator)实战
前言
在Blender中, 操作器(Operator)是它的核心. 用户通过各种操作器来创建和操作场景中的物体.
操作器对象继承自 class bpy.types.Operator(bpy_struct)
下面通过代码实例来学习它, 以下代码来源于https://docs.blender.org/api/2.79/bpy.types.Operator.html
#### 1 最简单的Operator
简单的信息打印
import bpy class HelloWorldOperator(bpy.types.Operator): bl_idname = "yy.hello_world" bl_label = "Minimal Operator" def execute(self, context): print("Hello World!") return {'FINISHED'} bpy.utils.register_class(HelloWorldOperator) # test call to the newly defined operator bpy.ops.yy.hello_world()
#### 2 Invoke
Operator.invoke用于在调用operator时从上下文初始化operator。Operator.invoke is used to initialize the operator from the context at the moment the operator is called.
import bpy class SimpleMouseOperator(bpy.types.Operator): """ This operator shows the mouse location, this string is used for the tooltip and API docs """ bl_idname = "wm.mouse_position" bl_label = "Invoke Mouse Operator" x = bpy.props.IntProperty() y = bpy.props.IntProperty() def execute(self, context): # rather than printing, use the report function, # this way the message appears in the header, self.report({'INFO'}, "Mouse coords are %d %d" % (self.x, self.y)) return {'FINISHED'} def invoke(self, context, event): self.x = event.mouse_x self.y = event.mouse_y return self.execute(context) bpy.utils.register_class(SimpleMouseOperator) # Test call to the newly defined operator. # Here we call the operator and invoke it, meaning that the settings are taken # from the mouse. bpy.ops.wm.mouse_position('INVOKE_DEFAULT') # Another test call, this time call execute() directly with pre-defined settings. bpy.ops.wm.mouse_position('EXEC_DEFAULT', x=20, y=66)
#### 3 调用文件选择器
Opens a file selector with an operator. The string properties ‘filepath’, ‘filename’, ‘directory’ and a ‘files’ collection are assigned when present in the operator Notice the invoke function calls a window manager method and returns {'RUNNING_MODAL'},
this means the file selector stays open and the operator does not exit immediately after invoke finishes.
import bpy class ExportSomeData(bpy.types.Operator): """Test exporter which just writes hello world""" bl_idname = "export.some_data" bl_label = "Export Some Data" filepath = bpy.props.StringProperty(subtype="FILE_PATH") @classmethod def poll(cls, context): return context.object is not None def execute(self, context): file = open(self.filepath, 'r') print(file.read()) file.close() #file.write("Hello World " + context.object.name) return {'FINISHED'} def invoke(self, context, event): context.window_manager.fileselect_add(self) return {'RUNNING_MODAL'} # Only needed if you want to add into a dynamic menu def menu_func(self, context): self.layout.operator_context = 'INVOKE_DEFAULT' self.layout.operator(ExportSomeData.bl_idname, text="Text Export Operator") # Register and add to the file selector bpy.utils.register_class(ExportSomeData) bpy.types.INFO_MT_file_export.append(menu_func) # test call bpy.ops.export.some_data('INVOKE_DEFAULT')
#### 4 对话框
import bpy class DialogOperator(bpy.types.Operator): bl_idname = "object.dialog_operator" bl_label = "Simple Dialog Operator" my_float = bpy.props.FloatProperty(name="Some Floating Point") my_bool = bpy.props.BoolProperty(name="Toggle Option") my_string = bpy.props.StringProperty(name="String Value") def execute(self, context): message = "Popup Values: %f, %d, '%s'" % \ (self.my_float, self.my_bool, self.my_string) self.report({'INFO'}, message) return {'FINISHED'} def invoke(self, context, event): wm = context.window_manager return wm.invoke_props_dialog(self) bpy.utils.register_class(DialogOperator) # test call bpy.ops.object.dialog_operator('INVOKE_DEFAULT')
#### 5 自定义绘图
By default operator properties use an automatic user interface layout. If you need more control you can create your own layout with a Operator.draw function.
import bpy class CustomDrawOperator(bpy.types.Operator): bl_idname = "object.custom_draw" bl_label = "Simple Modal Operator" filepath = bpy.props.StringProperty(subtype="FILE_PATH") my_float = bpy.props.FloatProperty(name="Float") my_bool = bpy.props.BoolProperty(name="Toggle Option") my_string = bpy.props.StringProperty(name="String Value") def execute(self, context): print("Test", self) return {'FINISHED'} def invoke(self, context, event): wm = context.window_manager return wm.invoke_props_dialog(self) def draw(self, context): layout = self.layout col = layout.column() col.label(text="Custom Interface!") row = col.row() row.prop(self, "my_float") row.prop(self, "my_bool") col.prop(self, "my_string") bpy.utils.register_class(CustomDrawOperator) # test call bpy.ops.object.custom_draw('INVOKE_DEFAULT')
#### 6 Modal执行
This operator defines a Operator.modal function that will keep being run to handle events until it returns {'FINISHED'} or {'CANCELLED'}.
import bpy class ModalOperator(bpy.types.Operator): bl_idname = "object.modal_operator" bl_label = "Simple Modal Operator" def __init__(self): print("Start") def __del__(self): print("End") def execute(self, context): context.object.location.x = self.value / 100.0 return {'FINISHED'} def modal(self, context, event): if event.type == 'MOUSEMOVE': # Apply self.value = event.mouse_x self.execute(context) elif event.type == 'LEFTMOUSE': # Confirm return {'FINISHED'} elif event.type in {'RIGHTMOUSE', 'ESC'}: # Cancel context.object.location.x = self.init_loc_x return {'CANCELLED'} return {'RUNNING_MODAL'} def invoke(self, context, event): self.init_loc_x = context.object.location.x self.value = event.mouse_x self.execute(context) context.window_manager.modal_handler_add(self) return {'RUNNING_MODAL'} bpy.utils.register_class(ModalOperator) # test call bpy.ops.object.modal_operator('INVOKE_DEFAULT')