Attaching a property on operator

I have a script that is supposed to add a modifier into an object.

The operator that executes the functioning code needs to have some properties to let the user have more options.

The problem is that when I actually write the Panel code I can’t figure out how to access that property.

Most tutorials suggest that a property can be attached in the scene for example and then its easy to access it via context in the draw method. However for a property in an operator is something else since if you try to access it though bpy.ops.myoperator is not available at all.

Any ideas on this?

Ask me to provide example code if needed.

You can pass a single property to an operator using the a ‘dot’ to reference the operator property upon invocation. I recommend passing the name of the current object. Then your operator can use that object name to fetch the object and examine any other custom properties it needs.

row.operator(“object.simple_operator”, icon=“INFO”).ob_name = obj.name

Here is an example of the Simple Operator mixed with the Simple Panel. The button appears at the bottom of the object context. This code will print the name of the object in the console when you click the operator button.


import bpy


class SimpleOperator(bpy.types.Operator):
    """Tooltip"""
    bl_idname = "object.simple_operator"
    bl_label = "Pass Name"
    
    #---> Add your property type here.
    ob_name = bpy.props.StringProperty(default = "")


    @classmethod
    def poll(cls, context):
        return context.active_object is not None


    def execute(self, context):
        #----> Fetch the passed value here.
        print("[%s]" % self.ob_name)
        return {'FINISHED'}
    
class HelloWorldPanel(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "Hello World Panel"
    bl_idname = "OBJECT_PT_hello"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"


    def draw(self, context):
        layout = self.layout


        obj = context.object


        row = layout.row()
        # ---> Pass your value here.
        row.operator("object.simple_operator", icon="INFO").ob_name = obj.name 




def register():
    bpy.utils.register_class(HelloWorldPanel)
    bpy.utils.register_class(SimpleOperator)




def unregister():
    bpy.utils.unregister_class(HelloWorldPanel)
    bpy.utils.unregister_class(SimpleOperator)




if __name__ == "__main__":
    register()


Hello, thanks for responding.

Based on your example, here is a modified version close to what I try to do.



import bpy


class SaySomethingOperator(bpy.types.Operator):
    bl_idname = "scene.sayoperator"
    bl_label = "Print Something"
    
    message = bpy.props.StringProperty(name="Message")
    optiona = bpy.props.BoolProperty(name="Option A")
    optionb = bpy.props.BoolProperty(name="Option B")


    def execute(self, context):
        print(self.message)
        return {'FINISHED'}


class SaySomethingPanel(bpy.types.Panel):
    bl_label = "Say Something"
    bl_idname = "SCENE_PT_saysomething"
    bl_space_type = "PROPERTIES"
    bl_region_type = "WINDOW"
    bl_context = "scene"


    def draw(self, context):
        layout = self.layout
        op = layout.operator("scene.sayoperator")
        layout.prop(op, "optiona")
        layout.prop(op, "optionb")
        layout.prop(op, "message")


        #bpy.types.SCENE_OT_sayoperator


def register():
    bpy.utils.register_class(SaySomethingPanel)
    bpy.utils.register_class(SaySomethingOperator)


def unregister():
    bpy.utils.unregister_class(SaySomethingPanel)
    bpy.utils.unregister_class(SaySomethingOperator)


if __name__ == "__main__":
    register()


As you can see what I want to do is to throw the properties into the operator to let it work stand alone by itself. I would not want to extend any other RNA type because I want these properties to live only in this operator. For example I do not want to extend the “object” type or the “scene” type.

As you can see I try to access the property from operator but two problems occur,

  1. That the properties are read only, I don’t know if I do this right but still searching.
  2. That I will have to add the operator first in order to get it’s instance, but for purposes of GUI I would like the button to appear last.

I guess I don’t get it. You can only pass one property better make sure it is a good one…eh?

Try this

/Edit/
Different thing, anyway, good luck.


def draw(self, context):
    layout = self.layout
    op = layout.operator("scene.sayoperator")
    op.optiona=True
    op.optionb=False
    op.message='Hello World'

1 Like

Having a look in it I guess that this is the most common way to do it, putting the properties in a common datatype (e.g. Scene) that can be reached from the context struct.


import bpy


class SaySomethingOperator(bpy.types.Operator):
    bl_idname = "scene.sayoperator"
    bl_label = "Print Something"
    message = bpy.props.StringProperty(name="Message")
    optiona = bpy.props.BoolProperty(name="Option A")
    optionb = bpy.props.BoolProperty(name="Option B")


    def execute(self, context):
        print("Message " + self.message)
        print("Option A " + str(self.optiona))
        print("Option B " + str(self.optionb))
        return {"FINISHED"}


class SaySomethingPanel(bpy.types.Panel):
    bl_label = "Say Something"
    bl_idname = "SCENE_PT_saysomething"
    bl_space_type = "PROPERTIES"
    bl_region_type = "WINDOW"
    bl_context = "scene"


    bpy.types.Scene.scenemessage = bpy.props.StringProperty(name="Message")
    bpy.types.Scene.sceneoptiona = bpy.props.BoolProperty(name="Option A")
    bpy.types.Scene.sceneoptionb = bpy.props.BoolProperty(name="Option B")


    def draw(self, context):
        layout = self.layout
        layout.label("Properties stored in the Scene type")
        layout.prop(context.scene, "scenemessage")
        layout.prop(context.scene, "sceneoptiona")
        layout.prop(context.scene, "sceneoptionb")


        layout.label("Calling the operator and passing the properties")
        op = layout.operator("scene.sayoperator")
        op.message = context.scene.scenemessage
        op.optiona = context.scene.sceneoptiona
        op.optionb = context.scene.sceneoptionb


        layout.label("Getting the properties of the operator (readonly)")
        layout.prop(op, "message")
        layout.prop(op, "optiona")
        layout.prop(op, "optionb")




def register():
    bpy.utils.register_class(SaySomethingPanel)
    bpy.utils.register_class(SaySomethingOperator)


def unregister():
    bpy.utils.unregister_class(SaySomethingPanel)
    bpy.utils.unregister_class(SaySomethingOperator)


if __name__ == "__main__":
    register()

But if I find any other alternative way I will let you know.

1 Like

You can’t add properties to panels, and operator properties aren’t accessible for panels other than the redo panel.

If they are supposed to be global, but not to be serialized to .blend, use bpy.types.WindowManager for your properties. You can use a PointerProperty and a PropertyGroup to organize them nicely.