2.5 scripting: changing enumeration properties?

This is a question about dropdown lists in 2.5x python panels. I want to create a panel with a dropdown list and some buttons. I also want to change the contents of the dropdown whenever a new object is selected (ie not a fixed list but one that is generated dynamically). At this stage, I cannot work out how to (re)populate the dropdown.

In the panel draw method I can do something like:


                layout.operator("mesh.primitive_fvg_useall", "Use all vertexes")
                layout.operator("mesh.primitive_fvg_usesel", "Use selected vertexes")
                layout.separator()
                layout.prop(rd, "vertex_groups", text="Vertex group")
                layout.operator("mesh.primitive_fvg_selfound", "Select")
                layout.operator("mesh.primitive_fvg_deselfound", "Deselect")
                layout.operator("mesh.primitive_fvg_removefound", "Remove from group")

I can set up the property doing something like

EnumProperty( attr="vertex_groups", name="Vertex groups", description="Vertex groups for current mesh", items = [], default = '0')

but I cannot see how to update the items.

Can anyone help me?

There is also something called a CollectionProperty; is that what I need? How do I use it?

Also, can I nest operators? I mean, could one operator (A) create a panel with further operators (B,C, etc) and then have operators B, C etc access the properties of operator A? If so, I suppose the EnumProperty could be generated each time as a property of operator A. But then the EnumProperty, and the items in it, are still set when the operator A is registered. So how would I set these items when operator A is called?

Here are a couple of links to my experiments with the 2.5 GUI.
http://blenderartists.org/forum/showthread.php?t=179522
http://blenderartists.org/forum/showthread.php?t=179694

These links deal with populating menus and processing click events.

Atom, thanks, but I had some specific questions, and they are not covered by those examples. In your case, you have two specific items in your menu (‘After Effects’ and ‘3DS Max’) and you can set these beforehand. What I want is to be able to vary the contents of the menu on the fly (depending on which vertexes are selected, actually).

I have been trying to come up with some code to do what I mentioned previously, and I have pasted below what I have done so far. Sorry for pasting it all in at such length, but this forum does not allow attachments. The code is enough to illustrate the user interface question that I was asking, but does not include thye actual functionality that I am intending to include (if you want to know, the 2.4x version is at http://blenderartists.org/forum/showthread.php?t=130053).

The code as it stands creates a panel with some buttons and a dropdown list, but there is nothing in the list. What I want (in this version) is for the list to contain all the vertex groups in the mesh, plus a dummy entry (this will change in the final version). However this is not working.

I am beginning to suspect that the current version of the Blender API does not allow dynamic generation of dropdowns. In that case, it might be necessary to submit a feature request.

#
import bpy
from bpy.props import *

class UseAll(bpy.types.Operator):
    bl_idname = "mesh.primitive_fvg_useall"
    bl_label = "Use All Vertexes"
    bl_register = True
    bl_undo = True

    def execute(self, context):
        return {'FINISHED'}

class UseSelected(bpy.types.Operator):
    bl_idname = "mesh.primitive_fvg_usesel"
    bl_label = "Use Selected Vertexes"
    bl_register = True
    bl_undo = True

    def execute(self, context):
        return {'FINISHED'}

class SelectFound(bpy.types.Operator):
    bl_idname = "mesh.primitive_fvg_selfound"
    bl_label = "Select"
    bl_register = True
    bl_undo = True

    def execute(self, context):
        return {'FINISHED'}

class DeselectFound(bpy.types.Operator):
    bl_idname = "mesh.primitive_fvg_deselfound"
    bl_label = "Deselect"
    bl_register = True
    bl_undo = True

    def execute(self, context):
        return {'FINISHED'}

class RemoveFound(bpy.types.Operator):
    bl_idname = "mesh.primitive_fvg_removefound"
    bl_label = "Remove from group"
    bl_register = True
    bl_undo = True

    def execute(self, context):
        return {'FINISHED'}

def get_groups(vgp):
        #vgp.clear()
        if len(vgp) == 0: vgp.append((0,'', ''))
        vgp[0] = (0,"(No group)","no group")
        obj = bpy.context.active_object
        i = 1
        for vg in obj.vertex_groups:
                if len(vgp) <= i: vgp.append((0,'', ''))
                vgp[i] = (i, vg.name, vg.name + ' x')
                i += 1
        print("%d groups replaced
" % len(vgp))

class VIEW3D_PT_FixVertexGroups(bpy.types.Panel):
    bl_space_type = "VIEW_3D"
    bl_region_type = "TOOLS"
    bl_label = "Fix Vertex Groups"

    vertex_groups = EnumProperty( attr="vertex_groups", name="Vertex groups", description="Vertex groups for current mesh", items = [], default = '0')

    def poll(self, context):
        if bpy.context.active_object:
           obj = bpy.context.active_object
           if obj.type == 'MESH' and obj.mode == 'EDIT': return True
        return False

    def draw(self, context):
        print('------ draw --------')
        rd = context.scene
        layout = self.layout

        if bpy.context.active_object:
           obj = bpy.context.active_object
           if obj.type == 'MESH' and obj.mode == 'EDIT':
                vertex_groups =  VIEW3D_PT_FixVertexGroups.vertex_groups
                print('svg: ', vertex_groups, '
')
                dict = vertex_groups[1]
                items = dict['items']
                get_groups(items)
                sc = context.scene
                layout.operator("mesh.primitive_fvg_useall", "Use all vertexes")
                layout.operator("mesh.primitive_fvg_usesel", "Use selected vertexes")
                layout.separator()
                layout.prop(self, "vertex_groups", text="Vertex group")
                layout.operator("mesh.primitive_fvg_selfound", "Select")
                layout.operator("mesh.primitive_fvg_deselfound", "Deselect")
                layout.operator("mesh.primitive_fvg_removefound", "Remove from group")

classes = [UseAll, UseSelected, SelectFound, DeselectFound, RemoveFound]

def register():
    for cl in classes: bpy.types.register(cl)
    bpy.types.register(VIEW3D_PT_FixVertexGroups)

def unregister():
    bpy.types.unregister(VIEW3D_PT_FixVertexGroups)
    for cl in classes: bpy.types.unregister(cl)

if __name__ == "__main__":
    register()

I’d like this too, if not already possible…

here;

http://blenderartists.org/forum/showthread.php?p=1520746

is an example that dynamically populates a list but it has a manual “update” function… (sorry, I didn’t read your code example, not fully up to speed pn 2.5 yet!

as I said though, if you get it working I’d be interested!

Michael, if you run this, then add some more materials, and then run it again, do the new materials appear in the dropdowns? Looking again at your example, I have managed to rewrite my script a bit, and it now works - once - but thereafter refuses to update the list. I will try working on it a bit more.

I have now rewritten the user interface to use rows of buttons rather than a drop-down list; that at least appears to be working now.

“My” example was by Crouch!
but anyway, the lack of an automatic solution: that’s what the manual “update” operator is for… not ideal!

I’d like to see your solution though!

I think that the old “popup” functionality of 2.4x was preferable in these cases as the popup could be populated when run so will always be up to date…

I think there’s new functions for popup panels in the last month or two… haven’t looked into it yet.

I really miss pupblock etc!

Broken hates them though!

Michael, I’ve posted my work in progress at http://blenderartists.org/forum/showthread.php?p=1606498#post1606498. It doesn’t work yet, and I have raised another thread at http://blenderartists.org/forum/showthread.php?t=184302 for my latest question about scripting. None of this any longer is relevant to dropdowns as I removed them from my script and just used lots of buttons instead (which does work).

I checked the code from the link I posted above against the current version of Blender 2.5 28112 and discovered that it no longer works. So this means code that is written against these preliminary builds may not work from version to version.

sorry to revive this old thread. just posting in case anyone else stumbles across it trying to find out how to create EnumProperty with a list of vertex groups…
try this…

class Whatever(bpy.types.Operator):
            bl_idname = ... etc
            ...etc
    
            vertex_group_list=[]
            #first list item must be id, name, description
            vertex_group_list.append(('VGID','Vertex Group','Vertex Group'))
            vertex_group_list.append(('-1','(Do not use vertex groups)','no group'))
            obj = bpy.context.active_object
            for index,vg in enumerate(obj.vertex_groups):
                          vertex_group_list.append((str(index), vg.name, vg.name))
            vertex_group_selected =bpy.props.EnumProperty(items=vertex_group_list,default='-1')

....

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

                         layout.prop(props, "vertex_group_selected")
...

note - the results of the user’s selection is stored in self.properties.vertex_group_selected as a string… you need to do int(self.properties.vertex_group_selected) to resolve it.

cheers

hmmm… it seems that actually that list of vertex groups is generated when you install the add-on or click run script in the script window(to register the operator), and not every time you run the operator. does anyone have any ideas?