Expose a Custom Property in UI

Hi, I want to make a UI Panel that controls various bones on my rig. It woud be neat to be able to expose some custom properties there instead of having to navigate to the bones every time.
I tried around with the prop() function in layout without success. I can access the property, for example this works and displays the right number:

row.label(text = str(pose.bones.get("Prop_Hand_L")["Prop_ID"]))

This does not work. I get an error only in the console saying “rna_uiItemR: property not found: PoseBone.Prop_ID”:

row.prop(pose.bones.get("Prop_Hand_L"),property = "Prop_ID")

What am I doing wrong?

When you create a property the arguments go like this row.prop(object, "attribute") such as for example bone, "location".

code updated

Thanks for your answer, sadly I still get the same error.

layout.prop(context.object.pose.bones["Prop_Hand_L"],"location")
layout.prop(context.object.pose.bones["Prop_Hand_L"],"Prop_ID")
        
val = context.object.pose.bones["Prop_Hand_L"]["Prop_ID"]
layout.label(text ="The property is accessible. It's value is: "+ str(val))

this produces the result below. The second time I call layout.prop does nothing.

grafik

What the console says? See window > toggle system console.

property not found: PoseBone.Prop_ID

OK I understood, it seems that a custom property needs to be registered. I think that is in pose mode.

https://docs.blender.org/api/current/bpy.props.html

import bpy

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

        layout.row().label(text="Active object is: " + context.object.name)
        layout.row().prop(context.object, "name")
        
        if context.mode == "POSE":
            
            layout.row().label(text="Existing Property")
            layout.row().prop(bpy.context.active_pose_bone, "location")

            layout.row().label(text="A Custom Property")
            layout.row().prop(bpy.context.active_pose_bone, "Prop_ID")

def register():
    bpy.utils.register_class(HelloWorldPanel)
    
    # assign a custom property to an existing type.
    # WARNING: PoseBone is only for the pose mode, Bone is for the Armature edit mode
    bpy.types.PoseBone.Prop_ID = bpy.props.StringProperty(name="Property ID")

def unregister():
    bpy.utils.unregister_class(HelloWorldPanel)
    
    del bpy.types.PoseBone.Prop_ID


if __name__ == "__main__":
    try: unregister()
    except: pass
    register()

That worked, thank you so much :smiley:
This is my panel now:
grafik