Using UiLists in Blender

Hello fel­low Pythonistas, in this tuto­r­i­al we’ll find out how to use UILists in our scripts and add-ons. If your users need to han­dle large amounts (or vari­able) amounts of data, this is the wid­get you want.

While you could just use a loop to draw wid­gets UILists have sev­er­al ben­e­fits over cus­tom-made solu­tions, like fil­ter­ing, search­ing and man­ag­ing space cor­rect­ly (less scrolling). It’s also how it’s done through­out the UI, so you can stay con­sis­tent with the rest of Blender.

By the way, I’m assum­ing you already know your way around the bpy and Python. This is an inter­me­di­ate tutorial.

Define the properties

First we have to cre­ate some prop­er­ties to hold the data on our list first. If we are pop­u­lat­ing the list with data of our own, we’ll need to define the struc­ture of the items in the list. You don’t need to define an item if you’re using exist­ing dat­a­blocks like mate­ri­als, or textures.

class ListItem(PropertyGroup):
    """Group of properties representing an item in the list."""

    name: StringProperty(
           name="Name",
           description="A name for this item",
           default="Untitled")

    random_prop: StringProperty(
           name="Any other property you want",
           description="",
           default="")

We’ll also need a Collection Property that will hold our list data, and an Integer prop­er­ty to hold the index num­ber. Let’s add them in our reg­is­ter() function.

def register():
    bpy.types.Scene.my_list = CollectionProperty(type = ListItem)
    bpy.types.Scene.list_index = IntProperty(name = "Index for my_list",
                                             default = 0)

Make the list widget

Now we can cre­ate the actu­al wid­get by extend­ing the UIList class. The UIList has one method (that we care about) called draw_item(). This method is called to draw each item in the list and it works pret­ty much like any oth­er draw­ing call­back in Blender. You can use labels, check box­es, oper­a­tor but­tons, etc.

draw_item() includes sev­er­al para­me­ters we can use:

  • data: Object con­tain­ing the col­lec­tion prop­er­ty (in our case, the scene)
  • item: The cur­rent item being drawn
  • icon: Calculated icon for the cur­rent item as an inte­ger (could be one of Blender’s or an icon for a material/texture/etc. depend­ing on the item)
  • active_data: Object con­tain­ing the active prop­er­ty of the col­lec­tion (in our case, the scene too)
  • active_propname: The name of the active prop­er­ty (index). In our case, it would be “list_index”)
  • index: Index of the cur­rent item (this one is optional)

Don’t for­get to reg­is­ter your UIList sub­class­es, or Blender won’t know about them.

class MY_UL_List(UIList):
    """Demo UIList."""

    def draw_item(self, context, layout, data, item, icon, active_data,
                  active_propname, index):

        # We could write some code to decide which icon to use here...
        custom_icon = 'OBJECT_DATAMODE'

        # Make sure your code supports all 3 layout types
        if self.layout_type in {'DEFAULT', 'COMPACT'}:
            layout.label(text=item.name, icon = custom_icon)

        elif self.layout_type in {'GRID'}:
            layout.alignment = 'CENTER'
            layout.label(text="", icon = custom_icon)

# ( inside register() )
    bpy.utils.register_class(MY_UL_List)

Now we can call it in our UI with the template_list() function.

        row = layout.row()
        row.template_list("MY_UL_List", "The_List", scene,
                          "my_list", scene, "list_index")

Let users modify the list

What good is a list if users can’t do any­thing with it? We’ll let users add, delete and move items up and down. These are the most basic oper­a­tions, you can eas­i­ly use them as a tem­plate to make your own.

Let’s begin by adding the operators.

class LIST_OT_NewItem(Operator):
    """Add a new item to the list."""

    bl_idname = "my_list.new_item"
    bl_label = "Add a new item"

    def execute(self, context):
        context.scene.my_list.add()

        return{'FINISHED'}

The add oper­a­tor is pret­ty straight­for­ward. Just call the add() method in the list.

class LIST_OT_DeleteItem(Operator):
    """Delete the selected item from the list."""

    bl_idname = "my_list.delete_item"
    bl_label = "Deletes an item"

    @classmethod
    def poll(cls, context):
        return context.scene.my_list

    def execute(self, context):
        my_list = context.scene.my_list
        index = context.scene.list_index

        my_list.remove(index)
        context.scene.list_index = min(max(0, index - 1), len(my_list) - 1)

        return{'FINISHED'}

For the delete op we first have to check we have some­thing to delete. We use the poll() method to check that there’s at least one item in the list. The cool thing about using poll() is that you it will also dis­able the oper­a­tor but­ton in the ui automatically.

Deleting is done by call­ing remove() with the list index (which will be what­ev­er we have select­ed in the ui).

Finally we have to fix the index. If we delete at the end of the list the index will have an invalid val­ue (larg­er than the length of the list), so we always move it back one posi­tion unless it’s zero.

class LIST_OT_MoveItem(Operator):
    """Move an item in the list."""

    bl_idname = "my_list.move_item"
    bl_label = "Move an item in the list"

    direction = bpy.props.EnumProperty(items=(('UP', 'Up', ""),
                                              ('DOWN', 'Down', ""),))

    @classmethod
    def poll(cls, context):
        return context.scene.my_list

    def move_index(self):
        """ Move index of an item render queue while clamping it. """

        index = bpy.context.scene.list_index
        list_length = len(bpy.context.scene.my_list) - 1  # (index starts at 0)
        new_index = index + (-1 if self.direction == 'UP' else 1)

        bpy.context.scene.list_index = max(0, min(new_index, list_length))

    def execute(self, context):
        my_list = context.scene.my_list
        index = context.scene.list_index

        neighbor = index + (-1 if self.direction == 'UP' else 1)
        my_list.move(neighbor, index)
        self.move_index()

        return{'FINISHED'}

Moving an item around takes some more con­sid­er­a­tion because we have to make sure the index stays valid.

The move() method allows us to swap items at two dif­fer­ent index­es. We only have to fig­ure out which index to swap with. Remember we start count­ing from zero, increas­ing downwards.

Finally we call our own move_index() method to change the index while clamp­ing it between 0 and the list length.

Item Data

Showing data from a list item is easy too, just use the index. Don’t for­get to make sure it’s valid though.

        if scene.list_index >= 0 and scene.my_list:
            item = scene.my_list[scene.list_index]

            row = layout.row()
            row.prop(item, "name")
            row.prop(item, "random_property")

The Final code

import bpy
from bpy.props import StringProperty, IntProperty, CollectionProperty
from bpy.types import PropertyGroup, UIList, Operator, Panel


class ListItem(PropertyGroup):
    """Group of properties representing an item in the list."""

    name: StringProperty(
           name="Name",
           description="A name for this item",
           default="Untitled")

    random_prop: StringProperty(
           name="Any other property you want",
           description="",
           default="")


class MY_UL_List(UIList):
    """Demo UIList."""

    def draw_item(self, context, layout, data, item, icon, active_data,
                  active_propname, index):

        # We could write some code to decide which icon to use here...
        custom_icon = 'OBJECT_DATAMODE'

        # Make sure your code supports all 3 layout types
        if self.layout_type in {'DEFAULT', 'COMPACT'}:
            layout.label(text=item.name, icon = custom_icon)

        elif self.layout_type in {'GRID'}:
            layout.alignment = 'CENTER'
            layout.label(text="", icon = custom_icon)


class LIST_OT_NewItem(Operator):
    """Add a new item to the list."""

    bl_idname = "my_list.new_item"
    bl_label = "Add a new item"

    def execute(self, context):
        context.scene.my_list.add()

        return{'FINISHED'}


class LIST_OT_DeleteItem(Operator):
    """Delete the selected item from the list."""

    bl_idname = "my_list.delete_item"
    bl_label = "Deletes an item"

    @classmethod
    def poll(cls, context):
        return context.scene.my_list

    def execute(self, context):
        my_list = context.scene.my_list
        index = context.scene.list_index

        my_list.remove(index)
        context.scene.list_index = min(max(0, index - 1), len(my_list) - 1)

        return{'FINISHED'}


class LIST_OT_MoveItem(Operator):
    """Move an item in the list."""

    bl_idname = "my_list.move_item"
    bl_label = "Move an item in the list"

    direction: bpy.props.EnumProperty(items=(('UP', 'Up', ""),
                                              ('DOWN', 'Down', ""),))

    @classmethod
    def poll(cls, context):
        return context.scene.my_list

    def move_index(self):
        """ Move index of an item render queue while clamping it. """

        index = bpy.context.scene.list_index
        list_length = len(bpy.context.scene.my_list) - 1  # (index starts at 0)
        new_index = index + (-1 if self.direction == 'UP' else 1)

        bpy.context.scene.list_index = max(0, min(new_index, list_length))

    def execute(self, context):
        my_list = context.scene.my_list
        index = context.scene.list_index

        neighbor = index + (-1 if self.direction == 'UP' else 1)
        my_list.move(neighbor, index)
        self.move_index()

        return{'FINISHED'}


class PT_ListExample(Panel):
    """Demo panel for UI list Tutorial."""

    bl_label = "UI_List Demo"
    bl_idname = "SCENE_PT_LIST_DEMO"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "scene"

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

        row = layout.row()
        row.template_list("MY_UL_List", "The_List", scene,
                          "my_list", scene, "list_index")

        row = layout.row()
        row.operator('my_list.new_item', text='NEW')
        row.operator('my_list.delete_item', text='REMOVE')
        row.operator('my_list.move_item', text='UP').direction = 'UP'
        row.operator('my_list.move_item', text='DOWN').direction = 'DOWN'

        if scene.list_index >= 0 and scene.my_list:
            item = scene.my_list[scene.list_index]

            row = layout.row()
            row.prop(item, "name")
            row.prop(item, "random_prop")


def register():

    bpy.utils.register_class(ListItem)
    bpy.utils.register_class(MY_UL_List)
    bpy.utils.register_class(LIST_OT_NewItem)
    bpy.utils.register_class(LIST_OT_DeleteItem)
    bpy.utils.register_class(LIST_OT_MoveItem)
    bpy.utils.register_class(PT_ListExample)

    bpy.types.Scene.my_list = CollectionProperty(type = ListItem)
    bpy.types.Scene.list_index = IntProperty(name = "Index for my_list",
                                             default = 0)


def unregister():

    del bpy.types.Scene.my_list
    del bpy.types.Scene.list_index

    bpy.utils.unregister_class(ListItem)
    bpy.utils.unregister_class(MY_UL_List)
    bpy.utils.unregister_class(LIST_OT_NewItem)
    bpy.utils.unregister_class(LIST_OT_DeleteItem)
    bpy.utils.unregister_class(LIST_OT_MoveItem)
    bpy.utils.unregister_class(PT_ListExample)


if __name__ == "__main__":
    register()

That’s it guys! You now have a basic but ful­ly func­tion­al UIList. If you’re inter­est­ed in more advanced top­ics like cus­tom fil­ters you can check the tem­plates in the text edi­tor (tem­plates > python > ui list).

All the posts you can read
TutorialsBlender, Python03.03.2021



40 Comments

  1. maes thierry(8 years ago)

    Thanks this tuto­r­i­al looks great. Only sug­ges­tion, maybe join the fin­ished script to see it work before decript/learn.
    regards,


    tmaes

    1. Diego Gangl(8 years ago)

      Hey, good idea! I’ve post­ed the a script at the end.

  2. iq bwv(8 years ago)

    thanks

  3. Marvin K. Breuer(8 years ago)

    The final code greate some errors: LIST_OT_DeleteItem.…

    1. Diego Gangl(8 years ago)

      Fixed, thanks for spot­ting that!

      1. Marvin K. Breuer(8 years ago)

        I use blender 2.76b.
        when i run the code in the texte­d­i­tor i have some trou­ble with the props.
        And it don´t want to reg­is­ter the my_list…
        Can you check this?

      2. Diego Gangl(8 years ago)

        Sorry about that. I don’t know why the edi­tor has been eat­ing so many lines and idents. It’s work­ing now, I also fixed the UI labels.

  4. Max Villafranca(6 years ago)

    Is the CollectionProperty doing the same job of PointerPropery, I have seen sev­er­al exam­ples and they seem inter­changable, do you mind elaborating?

    1. Diego Gangl(6 years ago)

      A PointerPropery points to a sin­gle instance of a PropertyGroup, while a CollectionProperty holds mul­ti­ple instances. If you’re only going to have one instance they could prob­a­bly be inter­change­able but in the case of a list you have to use a CollectionProperty.

  5. Rombout Versluijs(5 years ago)

    PS how would we imple­ment the dou­ble or ctrl click func­tion to update with­in the list? I find that works a bit nicer or more convenient

    1. Diego Gangl(5 years ago)

      You would have to use a layout.prop() with­out emboss instead of a label: layout.prop(item, ‘name’, text=”, emboss=False, icon=icon)

  6. Rombout Versluijs(4 years ago)

    Been a while and was look­ing for info about point­er­groups and point­er­prop­er­ties and all.
    PS there was anoth­er issue, the StringProperty random_property in PT_ListExample. It should be random_prop as you declared the StringProperty in the beginning

    1. Diego Gangl(4 years ago)

      Fixed, Thanks for mentioning!

  7. Jj(3 years ago)

    Hi

    I tried this under 2.83 While it works the list­ings do not show up any names, any added item int he list comes out nameless

    1. Diego Gangl(3 years ago)

      Hi, looks like I for­got to update this one for 2.8x. Fixed all the code, the only change is that the labels’ text has to be passed as a key­word argu­ment like this: layout.label(text=item.name, icon = custom_icon).
      Thanks for let­ting me know!

  8. jj(3 years ago)

    Hi

    That works thank you!

  9. sarka(3 years ago)

    Hi Diego
    Thanks for this tuto­r­i­al, sim­ple and well explained 🙂
    I would like to ini­tial­ize the list with data, but I can’t find how to do it.
    For exam­ple, from a variable:
    MyVar = [‘azer­ty’, ‘qsd­fgh’, ‘wxcvbn’, ‘poiuyt’, ‘mlkjhg’]
    Can you help me?

    Thanks

    1. Diego Gangl(3 years ago)

      Hi Sarka, you would need to ini­tial­ize them in the CollectionProperty you use to hold the val­ues for the list. You could do this in the reg­is­ter() func­tion of your addon, or at any point after you have reg­is­tered the col­lec­tion prop­er­ty into a vari­able (some­thing like bpy.types.Scene = my_collection). Then you can call my_collection.add(), which returns a new item in the col­lec­tion, and set the dif­fer­ent prop­er­ties there.

  10. Sarka(3 years ago)

    Thank you for your quick response Diego.
    I will test and I will come back to you if I can’t 🙂
    I’m start­ing in blender programming 😉

  11. Sarka(3 years ago)

    I used your exam­ple to test.
    In the Register func­tion, the CollectionProperty is declared with the line “bpy.types.Scene.my_list = CollectionProperty(type = ListItem)”. I added the line “bpy.types.Scene.my_list.add()”, but I get the error “AttributeError: ‘tuple’ object has no attribute ‘add’ ”.
    Sorry i’m very newbie 🙁

  12. Sarka(3 years ago)

    Ok, i found my error 🙂

    Thanks a lot for your help Diego 😉

    1. Diego Gangl(3 years ago)

      Ah you got it faster than I could reply.
      Glad to hear! Welcome to Blender scripting 🙂

  13. Passion3D(3 years ago)

    Hi Diego
    I fol­lowed your tuto­r­i­al and the direc­tions you gave to Sarka.
    In Scripting mode, every­thing works fine, but when I acti­vate my addon I get an error, When the RenderSettings_Init() func­tion is executed
    Here’s the code:
    #=========================
    def RenderSettings_Init():
    #=========================
    bpy.context.scene.my_list.clear()
    bpy.context.scene.active_index = 0
    for f in os.listdir(rendersettings_path):
    if f[-3::] == “dat”:
    item = bpy.context.scene.my_list.add()
    item.name = bpy.path.display_name(f).title()
    item.pathname = rendersettings_path

    #==================
    def register():
    #==================
    for cls in classes:
    bpy.utils.register_class(cls)
    bpy.types.Scene.my_list = CollectionProperty(type = ListItem)
    bpy.types.Scene.list_index = IntProperty(name = “Index for my_list”, default = 0)
    bpy.types.Scene.active_index = IntProperty(name = “Active set­tings”, default = 0)
    RenderSettings_Init()

  14. Passion3D(3 years ago)

    Here trace­back:
    Traceback (most recent call last):
    File “/usr//share/bforartists/2.91/scripts/modules/addon_utils.py”, line 382, in enable
    mod.register()
    File “/home/passion3d/.config/bforartists/2.91/scripts/addons/RenderSettings/__init__.py”, line 465, in register
    RenderSettings_Init()
    File “/home/passion3d/.config/bforartists/2.91/scripts/addons/RenderSettings/__init__.py”, line 289, in RenderSettings_Init
    bpy.context.scene.my_list.clear()
    AttributeError: ‘_RestrictContext’ object has no attribute ‘scene’

    1. Diego Gangl(3 years ago)

      Hi! hmm I see. The con­text in the reg­is­ter func­tion does­n’t include the scene yet (makes sense actu­al­ly). The oth­er option is to “lazy load” the list, in oth­er words, ini­tial­ize it when it is drawn for the first time. There’s two ways you can do that: you can add a flag (set to True ini­tial­ly) or you can check if the list is emp­ty. In either case you would add this as this at the top of the draw() func­tion in the UIList class. Something like:

      if first_run:
      RenderSettings_Init()
      first_run = False

  15. Passion3D(3 years ago)

    Hi
    Ok thanks Diego 😉

  16. Kirill(3 years ago)

    import bpy

    class ListItem(bpy.types.PropertyGroup):
    “””
    Group of prop­er­ties rep­re­sent­ing an item in the list.
    “””

    name: bpy.props.StringProperty(name=‘Name’, description=‘A name for this item’, default=‘Untitled’)
    random_prop: bpy.props.StringProperty(name=‘Any oth­er prop­er­ty you want’, descrip­tion=”, default=”)

    class MY_UL_List(bpy.types.UIList):
    def draw_item(self, con­text, lay­out, data, item, icon, active_data, active_propname, index):
    custom_icon = ‘OBJECT_DATAMODE

    if self.layout_type in {‘DEFAULT’, ‘COMPACT’}:
    layout.label(text=item.name, icon=custom_icon)
    elif self.layout_type in {‘GRID’}:
    layout.alignment = ‘CENTER
    layout.label(text=”, icon=custom_icon)

    class LIST_OT_NEW_ITEM(bpy.types.Operator):
    bl_idname = ‘my_list.new_item’
    bl_label = ‘Add a new item’

    def execute(self, context):
    context.scene.my_list.add()

    return {‘FINISHED’}

    class LIST_OT_DELETE_ITEM(bpy.types.Operator):
    “””
    Delete the select­ed item from the list.
    “””
    bl_idname = ‘my_list.delete_item’
    bl_label = ‘Deletes an item’

    @classmethod
    def poll(cls, context):
    return context.scene.my_list

    def execute(self, context):
    my_list = context.scene.my_list
    index = context.scene.list_index

    my_list.remove(index)
    context.scene.list_index = min(max(0, index — 1), len(my_list) — 1)
    return {‘FINISHED’}

    class LIST_OT_MOVE_ITEM(bpy.types.Operator):
    “””
    Move an item in the list.
    “””
    bl_idname = ‘my_list.move_item’
    bl_label = ‘Move an item in the list’

    direc­tion: bpy.props.EnumProperty(
    items=(
    (‘UP’, ‘Up’, ”),
    (‘DOWN’, ‘Down’, ”),
    )
    )

    @classmethod
    def poll(cls, context):
    return context.scene.my_list

    def move_index(self):
    “””
    Move index of an item ren­der queue while clamp­ing it.
    “””
    index = bpy.context.scene.list_index
    list_length = len(bpy.context.scene.my_list) — 1 # (index starts at 0)

    new_index = index + (-1 if self.direction == ‘UP’ else 1)
    bpy.context.scene.list_index = max(0, min(new_index, list_length))

    def execute(self, context):
    my_list = context.scene.my_list
    index = context.scene.list_index
    neigh­bor = index + (-1 if self.direction == ‘UP’ else 1)
    my_list.move(neighbor, index)
    self.move_index()
    return {‘FINISHED’}

    class PT_LIST_EXAMPLE(bpy.types.Panel):
    “””
    Demo pan­el for UI list Tutorial.
    “””

    bl_label = ‘UI_List Demo’
    bl_idname = ‘SCENE_PT_LIST_DEMO
    bl_space_type = ‘PROPERTIES
    bl_region_type = ‘WINDOW
    bl_context = ‘scene’

    def draw(self, context):
    lay­out = self.layout
    scene = context.scene
    row = layout.row()
    row.template_list(‘MY_UL_List’, ‘The_List’, scene, ‘my_list’, scene, ‘list_index’)
    row = layout.row()
    row.operator(‘my_list.new_item’, text=‘NEW’)
    row.operator(‘my_list.delete_item’, text=‘REMOVE’)
    row.operator(‘my_list.move_item’, text=‘UP’).direction = ‘UP
    row.operator(‘my_list.move_item’, text=‘DOWN’).direction = ‘DOWN

    if scene.list_index >= 0 and scene.my_list:
    item = scene.my_list[scene.list_index]

    row = layout.row()
    row.prop(item, ‘name’)
    row.prop(item, ‘random_prop’)

    def reg­is­ter():
    bpy.utils.register_class(ListItem)
    bpy.utils.register_class(MY_UL_List)
    bpy.utils.register_class(LIST_OT_NEW_ITEM)
    bpy.utils.register_class(LIST_OT_DELETE_ITEM)
    bpy.utils.register_class(LIST_OT_MOVE_ITEM)
    bpy.utils.register_class(PT_LIST_EXAMPLE)

    bpy.types.Scene.my_list = bpy.props.CollectionProperty(type=ListItem)
    bpy.types.Scene.list_index = bpy.props.IntProperty(name=‘Index for my_list’, default=0)

    def unreg­is­ter():
    del bpy.types.Scene.my_list
    del bpy.types.Scene.list_index
    bpy.utils.unregister_class(ListItem)
    bpy.utils.unregister_class(MY_UL_List)
    bpy.utils.unregister_class(LIST_OT_NEW_ITEM)
    bpy.utils.unregister_class(LIST_OT_DELETE_ITEM)
    bpy.utils.unregister_class(LIST_OT_MOVE_ITEM)
    bpy.utils.unregister_class(PT_LIST_EXAMPLE)

    if __name__ == ‘__main__’:
    register()

    1. Kirill(3 years ago)

      (for ctrl+c, ctrl+v purposes)

  17. Hal(2 years ago)

    This helped me grasp a lot of the prob­lems I had in try­ing to under­stand the UIList. I’ve been comb­ing the code for a few days and still don’t get a few key parts I need to understand.

    Just what class is my_list? I see it has the func­tions move() and add(), but I can’t fig­ure out where it is in the API doc­u­men­ta­tion so I can study it and find out what else it has.

    I see, in the com­mand row.template_list(“MY_UL_List”, “The_List”, scene, “my_list”, scene, “list_index”) you use “The_List,” but I don’t see any ref­er­ences to “The_List” any­where else in the script, so could you clar­i­fy what that represents?

    Also, in LIST_OT_NewItem() you use just context.scene.my_list.add(). Maybe this would be cov­ered in the API docs, but where is it get­ting what item to add?

    I want to cre­ate a UIList that includes cam­eras with­in the scene. I’d be able to select cam­eras and add them to the list (either one at a time or sev­er­al at once). So I’m not clear if I can use some­thing like my_list.add(sel_camera) to add a cam­era to the list or if it has to be get­ting the item to add from the UIList input. (And I’m not clear how I’d spec­i­fy for the UIList to use the cam­era names for dis­play instead of raw object data.)

    I know that’s a lot, but I’m real­ly try­ing to grasp this. Blender UI stuff is a lit­tle tough to get some­times and this seems to be the tough­est GUI object of all to deal with.

    1. Diego Gangl(2 years ago)

      Hi Hal,

      - my_list is a CollectionProperty. move() and add() come from it, every oth­er col­lec­tion­prop­er­ty in Blender has them if you check with the Python con­sole. Not sure why they are not doc­u­ment­ed in the API docs
      — “The_List” in this case is an iden­ti­fi­er. I think it’s an inter­nal thing because I’ve nev­er had any use for it. It has to be unique for each list though.
      — my_list.add() adds a new item to the col­lec­tion with default val­ues. The type of item that is added is set when cre­at­ing the CollectionProperty: CollectionProperty(type = ListItem). So the type of object is a ListItem
      — To dis­play cam­era names you need to change the draw_item() func­tion of the list. Something like “layout.label(text=camera.name)”
      — CollectionProperty(type = bpy.types.Camera) could do it for cam­eras (not test­ed though). But you might want to still use a cus­tom type, and have a PointerProperty for the cam­eras. Just in case you want to add more data attached to them in the future. Otherwise you would have to reg­is­ter those things in the cam­era objects themselves.
      — When you call add() it will add a default item. You need to catch that into a vari­able and set it to what­ev­er cam­era you want (the active object, the active cam in the scene, etc.)

      Good luck!

      1. Hal(2 years ago)

        Just want­ed to say, “Thanks!” It took me a while, but with your help here, I did get it all worked out.

      2. Diego Gangl(2 years ago)

        Awesome! \o/

  18. Paul(2 years ago)

    This arti­cle is awe­some, exact­ly what I was look­ing for. And that you keep main­tain­ing it after 6 years is incred­i­ble. Every ques­tion I could have pos­si­bly had, has already been asked and even answered by you. Thank you very much, Diego!

    1. Diego Gangl(2 years ago)

      Damn, 6 years already?
      No prob :D, thanks for the kind comment

  19. Vinny(2 years ago)

    The best one I’ve read about Blender python lists, I’ve tried the code but as all I’ve tried it gives a error. ” ‘Scene’ object has no attribute ‘my_list’ “. seems to be a night­mare for me at the moment to get any list to work! But as said before the best expla­na­tion I’ve read on the web about them. Thank you.

  20. Vinny(2 years ago)

    I take it back, Mr Fiddler here had changed a few things not ful­ly under­stand­ing what I was doing and messed the whole code up. Smashing job thank you, work­ing just fine now the Fiddler has not fid­dled!!! But now I can fid­dle and get my head around try­ing to use this for addon pref­er­ences, I’ve got it work­ing in the pref­er­ences pan­els but need to get my head around ref­er­enc­ing and stor­ing user input strings! But a big thanks to you I can now fid­dle in the direc­tion I want to go for the addon (I think).
    Kind regards and thank you,
    Vinny

  21. Vinny(2 years ago)

    Hi
    I’ve post­ed before after a suc­ces­ful code run, but I cant seem to find any ref­er­ence or point­ers on how I would get a list to work in the addon pref­er­ences pan­el, I can get this code to make a list box show and work fine BUT no mat­ter what I try I an unsuc­cess­ful at get­ting any of the list item added to save AS addon pref­er­ences, any point­ers as to how I would achieve this, I’ve tried to us a col­lec­tion prop­er­ty list­ed in the addon pref­er­ences but with errors on any way that I try?

  22. Garvin(2 years ago)

    Hi,
    Followed your steps and was able to install and demo the set­up. Thanks for the guide. 

    One ques­tion: If I want­ed to access the object data which is dis­played by the new Spreadsheet edi­tor how would i go about pars­ing or iter­at­ing through the source? I’m try­ing to pull the name and posi­tion prop­er­ty for the object but can’t seem to find the source object / col­lec­tion. Any help would be real­ly help full.

  23. Peeter(8 months ago)

    This arti­cle has helped me a lot, since I was look­ing for a way for users of my add-on to cre­ate their own list. Also, right now I’m try­ing to fig­ure out if there is any way for the UIList to store and retrieve the list, in oth­er words have blender remem­ber it as it remem­bers user pref­er­ences. I do have my own bpy.types.AddonPreferences class as well but I haven’t fig­ured out how to use that togeth­er with the UIList. I was won­der­ing if you have any advice, thanks!

    1. Peeter(8 months ago)

      At this point I stored my UIList val­ues in a prop­er­ty inside my bpy.types.AddonPreferences class and blender remem­bers them if I press Save Preferences. However, I’m not sure how the UIList could pop­u­late the list from AddonPreferences automatically.

Leave a Reply

Your email address will not be published.