Passing a list of objects to operator

Hi,

let’s imagine I have the following operator, and a simple panel to invoke it


import bpy
 
class Foo( bpy.types.Operator ):
    bl_idname = "screen.foo"
    bl_label = "Foo"
 
    def execute( self, context ):
        # A
        objects = bpy.data.objects

        for curr in objects:
            print(curr.location)
 
        return {'FINISHED'}
 
def register():
    bpy.utils.register_class( Foo )
 
def unregister():
    bpy.utils.register_class( Foo )
 
if __name__ == '__main__':
    register()

I then invoke it like this :


bpy.ops.screen.foo()

Now check the spot I marked with comment “A” in the operator; let’s imagine that instead of working on all objects, I want to operate on a subset of the objects, i.e. something like


bpy.ops.screen.foo(objects=[bpy.data.objects[0], bpy.data.objects[2], bpy.data.objects[4]])

Does anyone here know a way to achieve this cleanly?
Thanks

Can you declare an array:

arr=[objects[…],objects[…],…]

maybe using a loop to fill it up, then call …foo(arr) …?

In my code I use something like this.


def returnAllObjectNames ():
    # NOTE: This returns all object names in Blender, not scene specific.
    result = []
    for ob in bpy.data.objects:
        result.append(ob.name)
    return result 

def returnObjectNamesLike(passedName):
    # Return objects named like our passedName.
    result = []
    isLike = passedName
    l = len(isLike)
    all_obs = returnAllObjectNames()
    for name in all_obs:
        candidate = name[0:l]
        if isLike == candidate:
            result.append(name)
    return result

This way I can fetch a list of objects that are named similar and operate upon them.

numby, I think you misunderstood me :slight_smile: I know how to gather the list, what I don’t know is how to pass it as an operator parameter. There are types bpy.props.BoolProperty , bpy.props.StringProperty, bpy.props.FloatProperty, bpy.props.IntProperty, bpy.props.EnumProperty… but none that seems to let me pass lists of objects (or parameters of arbitrary type). And the operator can’t build the list itself, this just doesn’t fit into what I’m trying to do (to make a long story short, it’s an exporter, and we need a way to tell it which objects to export)

Atom: so you are suggesting to convert the objects into a string that would contain their names? This would indeed work, thanks for the advice; though it feels a bit hackish IMO, so if anyone knows a cleaner way to achieve this please let the world know

If it is an exporter, why not just look at the select tag of each object in the scene? If it is selected, it gets exported…less hackish, more integrated into the work-flow of the system.

Here is a way to pass a couple of variables to an operator.


import bpy

class cls_myClass(bpy.types.PropertyGroup):
    item = bpy.props.StringProperty(name="Item", description="Type the name of the object that will inherit this objects motion here.")
bpy.utils.register_class(cls_myClass)

class SimpleOperator(bpy.types.Operator):
    '''Tooltip'''
    bl_idname = "object.simple_operator"
    bl_label = "Simple Object Operator"
    the_list = bpy.props.CollectionProperty(type=cls_myClass)
    add = bpy.props.BoolProperty(default = True)
    item = bpy.props.StringProperty(default = "NA")

    def invoke(self, context, event):
        print("
Simple Operator.")
        print("Item=" + self.item)
        collection = self.the_list
        l =len(collection)
        for n in range(l):
            print(":" + collection[n].item)
        return {'FINISHED'}
       
    
class OBJECT_PT_hello(bpy.types.Panel):
    bl_label = "Hello World Panel"
    bl_space_type = "PROPERTIES"
    bl_region_type = "WINDOW"
    bl_context = "object"

    collection = []
    my_class = cls_myClass
    my_class.item = "Item #1"
    collection.append(my_class)
    my_class = cls_myClass
    my_class.item = "Item #2"
    collection.append(my_class)
       
    def draw(self, context):
        ob = context.object
        if ob != None:
            layout = self.layout
            layout.operator("object.simple_operator", icon = "ZOOMIN").add = True
            layout.operator("object.simple_operator", icon="ZOOMOUT", text="").item="My String"

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


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


if __name__ == "__main__":
    register()

One button passes a string (you could pass you list here if it was hackishly delimited).
The other button passes a Boolean.

I also left in an attempt at creating a collection of classes to pass to the operator, but that always end in some kind of read-only error (you may have encountered as well)

Atom, thanks for your answer and code snippet, this is interesting.

We can’t use the select flag because this is an exporter for a game, in two parts. The upper level part decides what needs to be exported, does quite a bit of logic to determine which objects are exporter together, which objects are exported alone, which are not exported at all, etc. And when it determined everything we invoke the model exporter, giving it a list of objects to export. So our current design has two different operators, and the main export operator needs to be able to communicate with the model exporter when it’s invoked. We could merge the two into a single operator but I think this would be ugly and break encapsulation and good design principles

So I think I’ll just go for a collection of object names, thanks :slight_smile:

EDIT: oops, I’d missed the part about read-only error -.- I’ll see what I can do

If the selection field is reserved, for some reason, you can always add another custom property to all objects in Blender and use that as your detection method.

thanks for the info, great parsing routine!