Operator with varying input

Hi All, hoping for some guidance in building my first Blender Add-On. I have a list of objects that are created in a custom side panel.

I want to have a “Focus” button for each of the objects in this list, that when triggered moves all of the objects in the scene such that the selected object is in the centre, and we see all other objects motion relative to that.

My Operator:

class SetCentreBody(bpy.types.Operator):
    bl\_idname = 'opr.set\_centre\_body'
    bl\_label = 'Focus'
    def execute(self, context):
        obj = context.object
        print("set focus @ " + str(obj.name))
        print("set focus @ " + str(obj.location))

Currently, my above function is taking the object from context, which is just the active object in the scene. What I want to be able to do is call this Operator with a different input, depending on which item/index in the list was selected. Is this possible?

To answer my own post:

  1. Add parameter we want, in this case of type IntProperty, to my SetCentreBody class:
class SetCentreBody(bpy.types.Operator):
    bl\_idname = 'opr.set\_centre\_body'
    bl\_label = 'Focus'

    # new line here ->
    thing_index: bpy.props.IntProperty(name="thing_index")

    def execute(self, context):
        obj = context.object
        print("set focus @ " + str(obj.name))
        print("set focus @ " + str(obj.location))
  1. When assigning this operator to the relevant row in my loop, set the body_index chaining the assignment after the .operator() call.
i = 0
for thing in list_of_things:
            col = self.layout.column()
            row = col.row()
            row.label(text='Thing: ' + i)
            row.operator('opr.set_centre_body').thing_index = i

Instead of

row.operator('opr.set_centre_body').thing_index = i

I prefer to assign the return value of row.operator() to a variable, because it makes it clear that you can have pass more than one argument this way:

op = row.operator('opr.set_centre_body')
op.thing_index = i

# more:
op.another_index = 42
op.whatever = "something"
1 Like

wonderful - ty

@B.Y.O.B - is there an equivalent to this for a PropertyGroup's update function? I’ve got a list being created, which in addition to including the above button, also has radius property that can adjust each thing in my list. I’ve just noticed a bug as per the above, where it’s only ever getting the active object.

my property:

    radius: bpy.props.FloatProperty(
        name='Radius (m)',
        default=1.0,
        min=0.0,
        update=update_radius,
        unit="LENGTH"
    )

adjacent update_radius function:

def update_radius(self, context):
    obj = context.object
    r = self.radius
    obj.scale = (r, r, r)
    for child in obj.children:
        child.scale = (1/r, 1/r, 1/r)

context.object is giving me the active object, whereas I actually want the object that the row in my list corresponds to. When adding it to the UI Panel:

col = self.layout.column()
row = col.row()
row.prop("radius")

You can get the parent of the custom property that is being edited with self.id_data in an update function, like so:

def update_radius(self, context):
    obj = self.id_data
    # ...
1 Like