Get which enum property was updated in a PropertyGroup

This is a very common problem with such tasks of automation using python lambdas (common in other languages, too). The thing is, the parameters of the lambda are evaluated at runtime, not when the lambda is assigned.

This prevents among other things the update from firing when the item registers.

But at runtime the variable key can only hold one value, the last one it has been assigned.

Usually you would solve it by using an initialized argument (I don’t know the exact term, you can look it up if interested)

update = lambda self, context, k=key: update(self, context, k),

But alas, Blender’s python API will not allow registering the property if the update function signature does not contain exactly two arguments : self and context (you can name them otherwise but they must be exactly two). So this is not a solution. See the docs : https://docs.blender.org/api/current/bpy.props.html#bpy.props.EnumProperty

You can however use another less common method which allows passing arbitrary data to a layout element.

bpy.types.UILayout.context_pointer_set

See What is context_pointer_set? - #6 by 1_conscience_0_dimen and https://blender.stackexchange.com/questions/203442/how-to-pass-a-bpy-data-objects-bpy-data-materials-etc-to-an-operator-from-th/203443#203443 for how-to use it.

In your case, here’s a stripped down example.

import bpy

def update(instance, context):
    print(context.enum)


class VIEW3D_PT_Test(bpy.types.Panel):
    bl_label ="Test Panel"
    bl_idname = "OBJECT_PT_hello"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "scene"

    def draw(self, context):
        for key in ("a", "b", "c"):
            row = self.layout.row()
            row.context_pointer_set("enum", context.scene.bl_rna.properties[f"my_enum_{key}"])
            row.prop(context.scene, f"my_enum_{key}")


def register():
    for key in ("a", "b", "c"):
        setattr(
            bpy.types.Scene, 
            f"my_enum_{key}",
            bpy.props.EnumProperty(
                items=(
                    ("1",) * 3,
                    ("2",) * 3,
                    ("3",) * 3,
                ),
                update=update,
            )
        )
    bpy.utils.register_class(VIEW3D_PT_Test)


if __name__ == "__main__":
    register()

Result :

Animation3

3 Likes