0
$\begingroup$

I have a CollectionProperty which contains an EnumProperty, and I need to programatically assign each EnumProperty's items attribute.

You can assign a value to something like IntProperty, BoolProperty, StringProperty etc.:

class Item(bpy.types.PropertyGroup):
    asdf = bpy.props.StringProperty()

bpy.utils.register_class(Item)


bpy.types.Scene.collection = bpy.props.CollectionProperty(type = Item)

# create a new item, assign its properties
item = bpy.context.scene.collection.add()
item.asdf = "asdf"

, but my siduation with EnumProperty is different here. The items attribute is taken in through an argument:

class Item(bpy.types.PropertyGroup):
    asdf = bpy.props.EnumProperty(
        # items argument required to initialize, just filled with empty values
        items = [
            ("", "", "")
        ]
    )

bpy.utils.register_class(Item)


bpy.types.Scene.collection = bpy.props.CollectionProperty(type = Item)

# create a new item, assign its properties
item = bpy.context.scene.collection.add()
item.asdf = [
    ("asdf", "asdf", "asdf")
]

So when you assign a value, you're just changing whatever the active enum value is. And it gets mad at you for trying to assign an array of tuples to a string.

The (best?) way to dynamically assign items appears to just be to delete it, and then re-assign it. This works with a normal EnumProperty:

del bpy.types.Scene.collection
bpy.types.Scene.collection = bpy.props.EnumProperty(
    items = [
        ("asdf", "asdf", "asdf")
    ]
)

, but it works differently when its part of a collection...

Calling the collection through bpy.types.Scene.collection returns a tuple, and attempting to execute del bpy.types.Scene.collection[0] throws AttributeError: 'builtin_function_or_method' object has no attribute 'asdf'.

How can I assign my own values to the EnumPropertys' items when they're in a CollectionProperty?


I'm definitely open to the possibility that I'm coming at this the wrong way, I've been getting acquainted with BPY for the past couple days and all the jargon's making my head spin a bit.

$\endgroup$
1
$\begingroup$

In case someone still need this, here is a minimal working example for blender 2.8:

import bpy

def add_items_from_collection_callback(self, context):
    items = []
    scene = context.scene
    for item in scene.my_items.values():
        items.append((item.some_str, item.some_str, ""))
    return items

class MyEnumItems(bpy.types.PropertyGroup):
    @classmethod
    def register(cls):
        bpy.types.Scene.my_enum_items = bpy.props.PointerProperty(type=MyEnumItems)

    @classmethod
    def unregister(cls):
        del bpy.types.Scene.my_enum_items

    asdf : bpy.props.EnumProperty(
        name="asdf",
        description="asdf",
        # items argument required to initialize, just filled with empty values
        items = add_items_from_collection_callback,
    )


class MyItem(bpy.types.PropertyGroup):
    @classmethod
    def register(cls):
        bpy.types.Scene.my_items = bpy.props.CollectionProperty(type=MyItem)

    @classmethod
    def unregister(cls):
        del bpy.types.Scene.my_items

    some_str : bpy.props.StringProperty(
        name = "asdf",
        default = ""
    )

class MY_OT_add_item(bpy.types.Operator):
    ''' add item to bpy.context.scene.my_items '''
    bl_label = "add item"
    bl_idname = "my.add_item"

    def execute(self, context):
        # create a new item, assign its properties
        item = bpy.context.scene.my_items.add()
        item.some_str = "asdf" + str(len(bpy.context.scene.my_items))
        return {'FINISHED'}

class MY_PT_simple_panel(bpy.types.Panel):
    bl_label = "Simple Panel"
    bl_idname = "MY_PT_simple_panel"
    bl_space_type = "VIEW_3D"   
    bl_region_type = "UI"
    bl_category = "simple panel"
    bl_context = "objectmode"

    def draw(self, context):
        layout = self.layout
        layout.operator("my.add_item")
        layout.prop(context.scene.my_enum_items, "asdf")

classes = (MyEnumItems, MyItem, MY_OT_add_item, MY_PT_simple_panel)
register, unregister = bpy.utils.register_classes_factory(classes)

if __name__ == "__main__":
    register()

in 3D View > Side bar > Simple Panel, click add item to add a new enum item for asdf

simple panel

| improve this answer | |
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.