How to use a prop_search() to return only objects that are armatures?

I’m writing an add-on where I want to use a prop_search() to let the user select from the objects in the scene. The only objects I want to see in the dropdown box are the objects which happen to be armatures.

Unfortunately, I cannot figure out how to do this. I have figured out how to use a prop_search() where it will pull back all of the objects in the scene, whether they are armatures, lights, cameras, or meshes:

    row.prop_search(bpy.context.preferences.addons['test_addon'].preferences, "my_armature_object_name", bpy.data, "objects", icon='OUTLINER_OB_MESH')

I have also figured out how to use a prop_search() so that it will pull back all of the “armature armatures” in a scene. What I mean is, there is the separate armature data property which may or may not have the same name as the main armature object:

    row.prop_search(bpy.context.preferences.addons['test_addon'].preferences, "my_armature_armature_name", bpy.data, "armatures", icon='ARMATURE_DATA')

In this screenshot, the top red arrow refers to the first code example above, where I am able to select from all of the objects (regardless of object type). The bottom red arrow refers to the second code example above, where it only sees the “armature armatures”.

How can I pull back things at the object level so that the user can choose from ONLY the objects which happen to be armatures?

Here is an add-on that demonstrates the issue. To run this, save this code in the addons directory in test_addon\__init__.py, then import the add-on in Blender through Edit → Preferences → Add-ons.

from bpy.props import *
import bpy
import bmesh
import os
import sys
import math

bl_info = {
    "name": "Test Addon",
    "author": "",
    "version": (1, 0, 0),
    "blender": (2, 80, 0),
    "location": "View3D > Properties > Rigging",
    "description": "TODO",
    "wiki_url": "",
    "tracker_url": "",
    "category": "3D View"}

class TestAddonPreferencesPanel(bpy.types.AddonPreferences):
    bl_idname = __module__
    my_armature_object_name: bpy.props.StringProperty(name = 'Armature Object', default = '', description = '')
    my_armature_armature_name: bpy.props.StringProperty(name = 'Armature Armature', default = '', description = '')

class TESTADDON_PT_Main(bpy.types.Panel):
    bl_idname = "TESTADDON_PT_Main"
    bl_label = "Test Addon"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_category = "Test"

    def draw(self, context):
	row = self.layout.row(align=True)
	row.prop_search(bpy.context.preferences.addons['test_addon'].preferences, "my_armature_object_name", bpy.data, "objects", icon='OUTLINER_OB_MESH')
	row = self.layout.row(align=True)
	row.prop_search(bpy.context.preferences.addons['test_addon'].preferences, "my_armature_armature_name", bpy.data, "armatures", icon='ARMATURE_DATA')

def register():
    bpy.utils.register_class(TestAddonPreferencesPanel)
    bpy.utils.register_class(TESTADDON_PT_Main)

def unregister():
    bpy.utils.unregister_class(TestAddonPreferencesPanel)
    bpy.utils.unregister_class(TESTADDON_PT_Main)

if __name__ == "__main__":
    register()

Any help would be greatly appreciated. Thanks!

Personally I would skip the prop search and keep it simple.

import bpy


class TESTADDON_PT_Main(bpy.types.Panel):
    bl_idname = "TESTADDON_PT_Main"
    bl_label = "Test Addon"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_category = "Test"

    def draw(self, context):
        row = self.layout.row(align=True)
        row.prop(context.scene, "my_pointer")


def p_filter(self, object):
    return object.type == 'ARMATURE'

def register():
    bpy.utils.register_class(TESTADDON_PT_Main)
    bpy.types.Scene.my_pointer = bpy.props.PointerProperty(
        type=bpy.types.Object,
        poll=p_filter,
        )

def unregister():
    bpy.utils.unregister_class(TESTADDON_PT_Main)
    del bpy.types.Scene.my_pointer

if __name__ == "__main__":
    register()

If you want to restrict to the active scene you can do something like:

def p_filter(self, object):
    return object.type == 'ARMATURE' and object.visible_get()
  • edit included delete for pointer in unregister.
3 Likes

Fantastic answer – thank you!