12
$\begingroup$

In my addon panel, how can I have an object selection box? And what data type would I use to store the the selected object?

It should look like this:

enter image description here

$\endgroup$
1

3 Answers 3

17
$\begingroup$

Building off of the answer by @CoDEmanX, here's a simple example:

import bpy    

class OBJECT_PT_HelloWorldPanel(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "Hello World Panel"
    bl_idname = "OBJECT_PT_hello"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"

    def draw(self, context):
        layout = self.layout
        scene = context.scene               
        layout.prop_search(scene, "theChosenObject", scene, "objects")


def register():
    bpy.utils.register_module(__name__)
    bpy.types.Scene.theChosenObject = bpy.props.StringProperty()


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


if __name__ == "__main__":
    register()

which gives:

enter image description here

How script works

The prop_search command lets the user choose one item from a bpy "collection" (in this case, the collection context.scene.objects) and saves the name of that item into a string (the string context.scene.theChosenObject).

If you need to use the object in a different part of script. Use

scene = context.scene
obj = scene.objects[scene.theChosenObject]

By the way, if you had wanted a "Materials Selection Box", you could have used

layout.prop_search(scene, "theChosenMaterial", bpy.data, "materials")

and similarly for textures, meshes, or any other bpy collection.

Limitations

We are only saving the name of the object (for example, scene.theChosenObject could be 'Cube'). If the user changes the name of the object, scene.theChosenObject will not change and you will not be able to use it to reference the object anymore.

See here for more on this problem.

$\endgroup$
2
  • 1
    $\begingroup$ Shouldn't the second code box say scene.object[scene.theChosenObject] rather than scene.object(scene.theChosenObject)? $\endgroup$ Commented Mar 23, 2014 at 15:15
  • 1
    $\begingroup$ I think unregister should del property from the Scene, not from the Object? i.e del bpy.types.Scene.theChosenObject $\endgroup$
    – Max Yari
    Commented Jun 17, 2019 at 16:30
10
$\begingroup$

Use prop_search(), a StringProperty and a CollectionProperty.

import bpy

enum_items = (
    ('FOO', 'Foo', ''),
    ('BAR', 'Bar', '')
)

class HelloWorldPanel(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "Hello World Panel"
    bl_idname = "OBJECT_PT_hello"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"

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

        obj = context.object

        col = layout.column()        
        col.prop_search(context.scene, "coll_string", context.scene, "coll", icon='OBJECT_DATA')

def populate_coll(scene):
    bpy.app.handlers.scene_update_pre.remove(populate_coll)
    scene.coll.clear()
    for identifier, name, description in enum_items:
        scene.coll.add().name = name

def register():
    bpy.utils.register_module(__name__)

    bpy.types.Scene.coll = bpy.props.CollectionProperty(
        type=bpy.types.PropertyGroup
    )

    bpy.types.Scene.coll_string = bpy.props.StringProperty()

    # Hack for testing
    bpy.app.handlers.scene_update_pre.append(populate_coll)


def unregister():
    bpy.utils.unregister_module(__name__)
    del bpy.types.Scene.coll
    del bpy.types.Scene.coll_string


if __name__ == "__main__":
    register()

For limitations please read:
Is it possible to use bpy.props.PointerProperty to store a pointer to an object?

$\endgroup$
4
$\begingroup$

Here is an updated answer built on previously accepted answer. Since 2.79, you can use bpy.props.PointerProperty to store references to blender data blocks.

You can then use prop instead of prop_search for selection box. prop_search is still useful if you want to select from a specific collection.

This solves the problem of modifying the object ( for example if you rename the object, the property will be updated). Also, deleting the object will not delete its data as, long as it is referenced somewhere. After all its references are removed, it gets deleted on file reload.

import bpy    

class OBJECT_PT_HelloWorldPanel(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "Hello World Panel"
    bl_idname = "OBJECT_PT_hello"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"

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


def register():
    bpy.utils.register_module(__name__)
    bpy.types.Scene.theChosenObject = PointerProperty(type=bpy.types.Object)


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


if __name__ == "__main__":
    register()
$\endgroup$
1

You must log in to answer this question.

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