2
$\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$
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$
  • $\begingroup$ Thanks a ton! This is a much better solution that what I'd hacked together in the past couple of days. Cheers! $\endgroup$ – Matthew Heimlich Sep 21 '14 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$ – Matthew Heimlich Sep 22 '14 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 '14 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 '17 at 19:08
2
$\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$
  • 1
    $\begingroup$ You know, a link to rigify would be really nice here. $\endgroup$ – Ludwik Apr 24 '15 at 17:24
  • $\begingroup$ @Ludwik, it comes with Blender. $\endgroup$ – ideasman42 Apr 25 '15 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 '15 at 7:47

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.