3
$\begingroup$

So I'm having some trouble wrapping my head around UI lists.

I've got a custom property on my object that stores a list of data like this:

ob["zones"] = [{"id": 1, "name": "foo", ...}, {[...]}]

I'd like to be able to read all of the name properties into the UI list, but can't figure out the best way to do it. There's currently a placeholder list box based off of the example template for material slots in my panel, but that's as far as I've gotten.

$\endgroup$

2 Answers 2

8
$\begingroup$

Create a CollectionProperty and supply an own class derived from bpy.types.PropertyGroup, in which you define your properties (it already comes with a StringProperty called "name").

In your UIList class, item refers to what you pass to layout.template_list() as 3rd and 4th argument, so the collection. Thus, item.id and item.name refer to entries in the collection Object.zones in the example below:

import bpy
from bpy.props import IntProperty, CollectionProperty
from bpy.types import Panel, UIList


class OBJECT_UL_zones(UIList):
    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
        split = layout.split(0.2)
        split.label(str(item.id))
        split.prop(item, "name", text="", emboss=False, translate=False, icon='BORDER_RECT')


class UIListPanelExample(Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "UIList Panel"
    bl_idname = "OBJECT_PT_ui_list_example"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"

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

        layout.template_list("OBJECT_UL_zones", "", ob, "zones", ob, "zones_index")


class Zone(bpy.types.PropertyGroup):
    # name = StringProperty()
    id = IntProperty()


def register():
    bpy.utils.register_module(__name__)
    bpy.types.Object.zones = CollectionProperty(type=Zone)
    bpy.types.Object.zones_index = IntProperty()

def unregister():
    bpy.utils.unregister_module(__name__)
    del bpy.types.Object.zones

if __name__ == "__main__":
    register()


    # Add an example entry every time this code is executed
    ob = bpy.context.object
    item = ob.zones.add()
    item.id = len(ob.zones)
    item.name = "Zone " + chr(item.id + 64)
$\endgroup$
4
  • $\begingroup$ Thanks a ton! This is a much better solution that what I'd hacked together in the past couple of days. Cheers! $\endgroup$ Sep 21, 2014 at 23:52
  • $\begingroup$ Another quick question: If I add for example three objects, giving index 1, 2, 3 respectively, is there a clean way to automatically have the index of entry 3 revert to index 2 when removing the existing entry 2? $\endgroup$ Sep 22, 2014 at 0:30
  • $\begingroup$ Is the index just a display element? If no, it doesn't make much sense to change indices everytime you delete items, does it? (If yes, just use layout.label(str(index)) in the UIList class.) Well, as long as you use an operator to remove items from the list, it is possible to access the collection and change whatever you have to. However, a user might manually remove() items from the collection and you won't have a chance to react on that. $\endgroup$
    – CodeManX
    Sep 22, 2014 at 10:27
  • $\begingroup$ I've been trying to use your example and make it appear on the Render Panel, but I get multiple failures. I thought I could simply change bl_context to "render" but its not that easy. Can you please shed some light on how to make this appear in other panels? Thanks $\endgroup$
    – kraken
    Jan 8, 2017 at 19:08
3
$\begingroup$

If you want UIList access you are going to have to create a Collection property (See bpy.props), See how rigify addon does this.

This means you'll have to use the higher level collection API functions (instead of assigning a custom-property like this).

(Would be good to make a simple example script for this answer, but reading rigify you can see how its done too - for now hope this helps)

$\endgroup$
3
  • 1
    $\begingroup$ You know, a link to rigify would be really nice here. $\endgroup$
    – Ludwik
    Apr 24, 2015 at 17:24
  • $\begingroup$ @Ludwik, it comes with Blender. $\endgroup$
    – ideasman42
    Apr 25, 2015 at 7:38
  • $\begingroup$ Oh, didn't know that. But I'd still say a link to the source here would be nice, because finding the source in the installation might not be as trivial. $\endgroup$
    – Ludwik
    Apr 25, 2015 at 7:47

You must log in to answer this question.

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