Learning about Operators #1

.start

Today, I finally got to learn the basics of Operators, thanks to the following links.
Based on some examples from the above links, I made a version for myself
A quick overview of my setup.
I wrote the program above in 4 steps as presented below

First

In this version, we are creating a new operator by sub-classing bpy.types.Operator and implementing a very basic execute method. Once the custom operator class is registered with Blender, its available to us.
import bpy

class MousePositionOperator(bpy.types.Operator):

    bl_idname = 'wm.mouse_position'
    bl_label = 'Mouse Position'
    
    def execute(self, context):
        self.report({'INFO'}, 'Hello')
        return {'FINISHED'}

bpy.utils.register_class(MousePositionOperator)

The operator is available from the Operator search menu in all contexts. We could implement a poll classmethod on Operators to make the operator locked to certain contexts. More on that later.

Second

import bpy

class MousePositionOperator(bpy.types.Operator):

    bl_idname = 'wm.mouse_position'
    bl_label = 'Mouse Position'
    
    x = bpy.props.IntProperty()
    y = bpy.props.IntProperty()
    
    def invoke(self, context, event):
        self.x, self.y = event.mouse_x, event.mouse_y
        wm = context.window_manager
        return wm.invoke_props_dialog(self)
    
    def execute(self, context):
        self.report({'INFO'}, "mX: {0} mY: {1}".format(self.x, self.y))
        return {'FINISHED'}

bpy.utils.register_class(MousePositionOperator)

Third

import bpy

class MousePositionOperator(bpy.types.Operator):

    bl_idname = 'wm.mouse_position'
    bl_label = 'Mouse Position'
    
    x = bpy.props.IntProperty()
    y = bpy.props.IntProperty()
    
    def invoke(self, context, event):
        self.x, self.y = event.mouse_x, event.mouse_y
        wm = context.window_manager
        return wm.invoke_props_dialog(self)
    
    def draw(self, context):
        layout = self.layout
        split = layout.split()
        column1 = split.column()
        column1.label(self.bl_idname)
        column2 = split.column()
        row = column2.row(align=True)
        row.prop(self, 'x')
        row.prop(self, 'y')
    
    def execute(self, context):
        self.report({'INFO'}, "mX: {0} mY: {1}".format(self.x, self.y))
        return {'FINISHED'}

bpy.utils.register_class(MousePositionOperator)


Fourth

Now we are providing a description for the operator and naming/describing the operator properties. Some comments are also being added.

import bpy

class MousePositionOperator(bpy.types.Operator):

    # operators python name with namespace bpy.ops. 
    # Upon registering this class, a type called 'WM_OT_mouse_position' is created under bpy.types
    bl_idname = 'wm.mouse_position'  
    bl_label = 'Mouse Position'
    bl_description = "Displays the mouse coordinates in the Info header"
    
    x = bpy.props.IntProperty(name='mX', description='X position of mouse')
    y = bpy.props.IntProperty(name='mY', description='Y position of mouse')
    
    def invoke(self, context, event):
        self.x, self.y = event.mouse_x, event.mouse_y
        wm = context.window_manager
        return wm.invoke_props_dialog(self)
    
    def draw(self, context):
        layout = self.layout
        split = layout.split()
        column1 = split.column()
        # Python name of the operator (bpy.ops)
        column1.label(self.bl_idname)
        # Type name of the operator (Dynamically created upon registration of this class)
        column1.label(self.__class__.__name__)
        column2 = split.column()
        row = column2.row(align=True)
        row.prop(self, 'x')
        row.prop(self, 'y')
    
    def execute(self, context):
        self.report({'INFO'}, "mX: {0} mY: {1}".format(self.x, self.y))
        return {'FINISHED'}

bpy.utils.register_class(MousePositionOperator)

Changes made to Info Header

        if hasattr(bpy.types, 'WM_OT_mouse_position'):
            operator = layout.operator('wm.mouse_position')

            operator.x = -1
            operator.y = -1


As you can see, we can update the operator property values after creating an instance of it in the user interface.
Operator in Action
Next step was to introspect the operator in the Console.
Tried to execute the operator from the Console. 
And also the Operator's type
Based on the bl_idname, when we register the class, Blender creates a type called WM_OT_mouse_position under bpy.types

Errors Encountered

Some of the errors encountered while developing the wm.mouse_position operator.

Function.result expected a set

location: <unknown location>:-1
RuntimeError: class WM_OT_mouse_position, function execute: incompatible return value , str(, Function.result expected a set, not a NoneType)
I just scratched the surface for today, and am looking forward to writing more Operators. But, if you want to get your hands dirty with the code, you can leverage on the templates provided in the Blender distribution and which can be accessed from the Text Editor Templates menu.

.end
satishgoda at gmail dot com

Comments

Popular Posts