I need to have a collection that stores different classes (would contain only 2 classes specifically).

In other words, is like I'd like that collection to "act" as some kind of (generic) List.

But not sure if it's possible. As the API says, I need the collection to be a subclass of PropertyGroup. In that property group, to store a class object I need to use a PointerProperty (if I'm not mistaken).

BUT, to define that PointerProperty, I must define their class. So is like I'd have to choose the class I will add to the collection (only one).

I saw that both classes derives from bpy.types.bpy_struct, so I thought about defining bpy.props.PointerProperty(type=bpy.types.bpy_struct), but is not possible, gives an error.

The other option I have is to make a PropertyGroup with 2 props; one prop for storing the class A, and another prop for storing class B. And then check if one or the other property is None (so I know which class stores). But this feels wrong.

So, is it possible to have a collection that acts as a list?

Thank you so much for the help.


1 Answer 1


You can nest a PropertyGroup inside another PropertyGroup using PointerProperty and use that another PropertyGroup again inside another PropertyGroup using CollectionProperty.

import bpy
from bpy.types import Panel, UIList, Operator, PropertyGroup
from bpy.props import *

class CUSTOM_PG_property_group(PropertyGroup):

    text : StringProperty(default='Text')

class CUSTOM_PG_collection(PropertyGroup):

    object : PointerProperty(type=bpy.types.Object)
    label : PointerProperty(type=CUSTOM_PG_property_group)

class CUSTOM_PG_collections(PropertyGroup):

    items : CollectionProperty(type=CUSTOM_PG_collection)
    item_index : IntProperty()

class CUSTOM_UL_collection(UIList):

    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
        row = layout.row(align=True)
        row.prop(item.label, 'text', text='', emboss=False)
        row.prop(item, 'object', text='', emboss=False)

class CUSTOM_OT_collection_item_add(Operator):

    bl_label = "Add a Item"
    bl_idname = "xx.collection_item_add"

    def execute(self, context):
        collections = context.scene.collections
        return {'FINISHED'}

class CUSTOM_OT_collection_item_remove(Operator):

    bl_label = "Remove a Item"
    bl_idname = "xx.collection_item_remove"

    def execute(self, context):
        collections = context.scene.collections

        return {'FINISHED'}

class HelloWorldPanel(Panel):
    bl_label = "Hello World Panel"
    bl_idname = "OBJECT_PT_hello"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = "Test"

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

        collections = context.scene.collections

        row = layout.row()
        row.template_list('CUSTOM_UL_collection', '', dataptr=collections, active_dataptr=collections, propname='items', active_propname='item_index', rows=4)
        col = row.column(align=True)
        col.operator('xx.collection_item_add', text='', icon='ADD')
        col.operator('xx.collection_item_remove', text='', icon='REMOVE')

classes = (

def register():
    for cls in classes:

    bpy.types.Scene.collections = bpy.props.PointerProperty(type=CUSTOM_PG_collections)

def unregister():
    for cls in classes:
    del bpy.types.Scene.collections

if __name__ == "__main__":
  • $\begingroup$ Thank you so much for the help, I wasn't aware of that $\endgroup$
    – Ommadawn
    Jul 9, 2023 at 18:47

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .