Dynamic enumeration problem

Hi.

Im trying to draw a Panel with an enumProperty that contains the object’s names in my scene.
I can do that but i dont know how to “update” this enum property if i add an object to the scene.

Anyone know if this is posible?
Thanks in advance.

http://blenderartists.org/forum/asset.php?fid=133615&uid=37229&d=1306029893
By the way the code im using for the example above is this:


import bpy

#quotes a string
def qu(cad):
    return "'"+cad+"'"

#returns a tuple with object's names
def objectsnames():
    
    items = "("
    for i, obj in enumerate(bpy.context.scene.objects):         
        items+="("+qu(str(i))+","+qu(obj.name)+",''), "
            
    items = items[0:-2]+")"
    
    myitems = eval(items)
    
    return myitems


class OBJECT_PT_hello(bpy.types.Panel):
    bl_label = "Hello World Panel"
    bl_space_type = "PROPERTIES"
    bl_region_type = "WINDOW"
    bl_context = "object"

    myitems = objectsnames()
    bpy.types.Scene.list = bpy.props.EnumProperty(name="Objects",items=myitems)
    
    def draw(self, context):
        layout = self.layout

        obj = context.object

        row = layout.row()
        row.label(text="Hello world!", icon='WORLD_DATA')

        row = layout.row()
        row.label(text="Active object is: " + obj.name)
        row = layout.row()
        row.prop(obj, "name")

        row = layout.row()
        row.prop(context.scene, "list")

def register():
    bpy.utils.register_class(OBJECT_PT_hello)
def unregister():
    bpy.utils.unregister_class(OBJECT_PT_hello)

if __name__ == "__main__":
    register()

http://misc.cgcookie.netdna-cdn.com//pencil.pnghttp://misc.cgcookie.netdna-cdn.com//pencil.pnghttp://misc.cgcookie.netdna-cdn.com//pencil.pnghttp://misc.cgcookie.netdna-cdn.com//pencil.png

Attachments


I’m pretty certain it’s impossible. I asked a similar question to ideasman a few days ago and he explained that once an EnumProperty is created you can’t change the items it contains using python. You could destroy and recreate the EnumProperty, but if it is visible in the UI that could crash Blender, so it isn’t a good solution.

Thanks for the answer Crouch, i was afraid of that.
I was trying unregistering and registering again but as u said its not a good way.
Ill try another kind of layout for my panel.

try with a collection like this one
might work i hope


 
 import bpy
 
## class where the custom properties for the Collection will be nested
## (each entry of the collection will derive its Properties from this Class
## and can hold own values for each property)
 
class PropertyGroup(bpy.types.PropertyGroup):
 pass
 
bpy.utils.register_class(PropertyGroup) 
 
 
bpy.types.Object.mychosenObject = bpy.props.StringProperty()
 
## create CollectionProperty and link it to the property class
bpy.types.Object.myCollection = bpy.props.CollectionProperty(type = PropertyGroup)
bpy.types.Object.myCollection_index = bpy.props.IntProperty(min = -1, default = -1)
## create Properties for the collection entries:
PropertyGroup.mystring = bpy.props.StringProperty()
PropertyGroup.mybool = bpy.props.BoolProperty(default = False)
 
 
 
## create operator to add or remove entries to/from  the Collection
class OBJECT_OT_add_remove_Collection_Items(bpy.types.Operator):
 bl_label = "Add or Remove"
 bl_idname = "collection.add_remove"
 __doc__ = "Simple Custom Button"
 
 
 
 add = bpy.props.BoolProperty(default = True)
 
 def invoke(self, context, event):
  add = self.add
  obj = context.object
  collection = obj.myCollection
  if add:
   collection.add()         # This add at the end of the collection list
  else:
   index = obj.myCollection_index
   collection.remove(index)       # This remove on item in the collection list function of index value
   
 return {'FINISHED'} 
 
class OBJECT_PT_ObjectSelecting(bpy.types.Panel):
 
 bl_label = "Object Selecting"
 bl_space_type = "PROPERTIES"
 bl_region_type = "WINDOW"
 bl_context = "object"
 
 def draw(self, context):
  obj = context.object
  layout = self.layout
  
  ##show collection in Panel:
  row = layout.row()
  row.template_list(obj, "myCollection", obj, "myCollection_index")        # This show list for the collection
  ##show add/remove Operator
  col = row.column(align=True)
  col.operator("collection.add_remove", icon="ZOOMIN", text="")         # This show a plus sign button
  col.operator("collection.add_remove", icon="ZOOMOUT", text="").add = False     # This show a minus sign button
  
  ##change name of Entry:
  if obj.myCollection:
   entry = obj.myCollection[obj.myCollection_index]
   layout.prop(entry, "name")
   
   ##show self created properties of myCollection
   layout.prop(entry, "mystring")
   layout.prop(entry, "mybool")
  
  ### search prop to search in myCollection:
  layout.prop_search(obj, "mychosenObject",  obj, "myCollection")
    
    
bpy.utils.register_class(OBJECT_PT_ObjectSelecting) 
bpy.utils.register_class(OBJECT_OT_add_remove_Collection_Items) 
#bpy.utils.register_class(PropertyGroup) 
 
  
 

sorry did a mistake in first sample i did

this works in 36707

You could do it with menus… excuse the bad names… copy paste effort.


import bpy

#quotes a string
def qu(cad):
    return "'"+cad+"'"

#returns a tuple with object's names
def objectsnames():
    
    items = "("
    for i, obj in enumerate(bpy.context.scene.objects):         
        items+="("+qu(str(i))+","+qu(obj.name)+",''), "
            
    items = items[0:-2]+")"
    
    myitems = eval(items)
    
    return myitems

class BranchMenu(bpy.types.Menu):
    bl_idname = "mocapmadness.branchmenu"
    bl_label = "Branch to Action"

    def draw(self, context):
        objects = context.scene.objects
        
        layout = self.layout
        for object in objects:

                
            text = object.name  
            layout.operator("object.select_name", text=text).name=text

               
class OBJECT_PT_hello(bpy.types.Panel):
    bl_label = "Hello World Panel"
    bl_space_type = "PROPERTIES"
    bl_region_type = "WINDOW"
    bl_context = "object"

    myitems = objectsnames()
    bpy.types.Scene.list = bpy.props.EnumProperty(name="Objects",items=myitems)
    
    def draw(self, context):
        layout = self.layout

        obj = context.object

        row = layout.row()
        row.label(text="Hello world!", icon='WORLD_DATA')

        row = layout.row()
        row.label(text="Active object is: " + obj.name)
        row = layout.row()
        row.prop(obj, "name")

        row = layout.row()
        row.prop(context.scene, "list")
        row.menu("mocapmadness.branchmenu",text=context.object.name)

def register():
    bpy.utils.register_class(BranchMenu)
    bpy.utils.register_class(OBJECT_PT_hello)
def unregister():
    bpy.utils.unregister_class(OBJECT_PT_hello)

if __name__ == "__main__":
    register()


Thank you very much, im not very familiar with the layout, i will definitely try your code.

i got Ghost in blender

i tried last script

and strangely enough i get objects name from another world ?

don’t exist in the file i have there or in outliner ?

where are these coming form ?

No probs… there is a way to do this with a prop_search looking at the bpy.data.objects but the menu method lets you filter the menu… only selecting mesh objects for instance.

Both examples are great. Thanks a lot.

There is a workaround but it’s very bad …
correct code:


import bpy

#quotes a string
def qu(cad):
    return "'"+cad+"'"

#returns a tuple with object's names
def objectsnames():
    j=0
    items = "("
    for i, obj in enumerate(bpy.context.scene.objects):         
        items+="("+qu(str(i))+","+qu(obj.name)+",''), "
        j += 1
            
    items = items[0:-2]+")"
    
    myitems = eval(items)
    bpy.types.Scene.listObj = bpy.props.EnumProperty(name="Objects",items=myitems)
    bpy.types.Scene.numList = bpy.props.IntProperty(name='NumList',default=j)
    #return myitems

print(dir(bpy.props.EnumProperty))
class OBJECT_PT_hello(bpy.types.Panel):
    bl_label = "Hello World Panel"
    bl_space_type = "PROPERTIES"
    bl_region_type = "WINDOW"
    bl_context = "object"

    myitems = objectsnames()
    #bpy.types.Scene.list = bpy.props.EnumProperty(name="Objects",items=myitems)
    def __init__(self):
        lt = bpy.context.scene.listObj
        num = bpy.context.scene.numList
        if len(bpy.context.scene.objects) != num:
            objectsnames()
            
    def draw(self, context):
        layout = self.layout

        obj = context.object

        row = layout.row()
        row.label(text="Hello world!", icon='WORLD_DATA')

        row = layout.row()
        row.label(text="Active object is: " + obj.name)
        row = layout.row()
        row.prop(obj, "name")

        row = layout.row()
        row.prop(context.scene, "listObj")

def register():
    bpy.utils.register_class(OBJECT_PT_hello)
def unregister():
    bpy.utils.unregister_class(OBJECT_PT_hello)

for the second script

at bottom you avhe first button which shows the list of objects
but if you add new object this list is not upated

but first is updated in the second button on the right for menu

why is the first lit not upated cause this one i made inside the draw button!

@orinoco56
Thanks for trying orinoco, but i didnt realise that bpy.types.Menu displays the same as an enumerator with the advantage to add items. Enumerators are meant to be unique and independent from the context.

@RickyBlender
The first one isnt updating because was made (by me) using enumProperty and not bpy.types.Menu

i see list prop but does not give any error on trying to update scene prop

like out of context !

also i got 36707

and last script is not doing anything
and no error

any changes to be made to see panel in object panel?