1
$\begingroup$

I want to put four or five choices in an EnumProperty so I can pick a choice of actions. Most choices won't need additional input, but one (possibly two) will need more input. For example, let's say Choice 4 needs a StringProperty and Choice 5 needs a BooleanProperty.

If I pick 1, 2, 3, or 5, I'd like both of the extra properties hidden, but if I pick Choice 4 from the Enum, I'd like the row with the StringProperty to appear. If I pick 5, I'd like the StringProperty (From 4) to disappear and the BooleanProperty to appear.

Also, I want to specify, with another row, info on the current status, so when the EnumProperty changes, I need to make another row visible or not and I need to change the string in my status row.

I've been looking this over and it looks like if a set the text in a row to something like:

row.label(text="My test status: " + context.scene.TestStatus)

and I do this along the way:

bpy.types.Scene.TestStatus = "Current Test Status"

that whenever I change the value of bpy.types.Scene.TestStatus that the value in the row on the panel will change. Am I right about that? Does Blender handle all that so I don't have to do something like "on value change" for the Enum? I've seen a few partial examples, but I'm not quite sure how this works. The same is true in reading the Enum value - where would I put the code to read the Enum value and show or hide the String and Boolean properties?

$\endgroup$
4
  • 1
    $\begingroup$ Basically this related to the distinction between a class and an instance of the class. Go as far to say you are one instance of "Homo sapiens" speculatively should the "creator" change the class property animals.types.HomoSapiens.hair_color = (1, 0, 0) you would wake up a ranga. $\endgroup$
    – batFINGER
    Commented Mar 10, 2021 at 8:31
  • $\begingroup$ Testing the identifier of the currently selected value in your enumerated list will allow you to 'show/hide' rows in a panel, but you're losing me when you say you want to make a row visible on a change of your enum property. Do you mean any time you select a different item in your list? Finally I dont think you mean change bpy.types.Scene.TestStatus I think you mean change context.scene.TestStatus = "Current Test Status" $\endgroup$
    – Ratt
    Commented Mar 10, 2021 at 9:10
  • $\begingroup$ @batFINGER Thanks - that helps. And if that DID happen, at least I wouldn't be "rude and not ginger!" (Couldn't help the Doctor Who reference!) $\endgroup$
    – Tango
    Commented Mar 10, 2021 at 19:04
  • $\begingroup$ @Ratt Still working my way down to your answer, but, yes, basically whenever a different value in the Enum is selected, I want it to change what's visible and the text in the separate row. $\endgroup$
    – Tango
    Commented Mar 10, 2021 at 19:07

1 Answer 1

4
$\begingroup$

Given a defined enumerated list:

proplist: bpy.props.EnumProperty(
    items=(("BoolProperty", "Bool", "Boolean"),
    ("BoolVectorProperty", "Bool", "Boolean"), # duplicate name, desc
    ("FloatProperty", "Float", "Floating Point"),
    ("FloatVectorProperty", "Float Vector", "Floating Point Vector"),
    ("IntProperty", "Int", "Integer"),
    ("IntVectorProperty", "Int Vector", "Integer Vector"),
    ("PointerProperty", "Pointer", "Pointer Property"),
    ),
    name="proplist",
    description="Selectable properties to add",
    default="BoolProperty",
    )

The items require an identifier (unique to the list), a name (potentially duplicated internal to a list), and a description (potentially duplicated internal to a list).

items (sequence of string tuples or a function) – sequence of enum items formatted: [(identifier, name, description, icon, number), ...]. The first three elements of the tuples are mandatory.

As such any test should be performed against the identifier of the list.

Within the panel you can then perform logical test:

if items[props.proplist].identifier == 'PointerProperty':
    col.prop(props, 'test_str')
if items[props.proplist].identifier == 'BoolProperty':
    col.prop(props, 'test_bool')

And provide information based on the selection:

items = props.bl_rna.properties['proplist'].enum_items
col.label(text=f"item [ identifier ] : {items[props.proplist].identifier}")
col.label(text=f"item [ name ] : {items[props.proplist].name}")
col.label(text=f"item [ description ] : {items[props.proplist].description}")

An overall example script below:

import bpy


class TEST_PG(bpy.types.PropertyGroup):
    proplist: bpy.props.EnumProperty(
        items=(("BoolProperty", "Bool", "Boolean"),
        ("BoolVectorProperty", "Bool", "Boolean"), # duplicate name, desc
        ("FloatProperty", "Float", "Floating Point"),
        ("FloatVectorProperty", "Float Vector", "Floating Point Vector"),
        ("IntProperty", "Int", "Integer"),
        ("IntVectorProperty", "Int Vector", "Integer Vector"),
        ("PointerProperty", "Pointer", "Pointer Property"),
        ),
        name="proplist",
        description="Selectable properties to add",
        default="BoolProperty",
        )
    test_str: bpy.props.StringProperty(
        name="test_str",
        description="str",
        default="Junk",
        )
    test_bool: bpy.props.BoolProperty(
        name="test_bool",
        description="bool",
        default=True,
        )


class VIEW3D_PT_test():
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = "Test Panel"


class TEST_PT_sub_01(VIEW3D_PT_test, bpy.types.Panel):
    bl_idname = "VIEW3D_PT_test_panel_1"
    bl_label = "Test Panel 1"
    

    def draw(self, context):
        props = context.scene.my_property_group
        layout = self.layout
        box = layout.box()
        col = box.column(align=True)
        col.prop(props, "proplist")
        items = props.bl_rna.properties['proplist'].enum_items
        col.label(text=f"item [ identifier ] : {items[props.proplist].identifier}")
        col.label(text=f"item [ name ] : {items[props.proplist].name}")
        col.label(text=f"item [ description ] : {items[props.proplist].description}")
        
        if items[props.proplist].identifier == 'PointerProperty':
            col.prop(props, 'test_str')
        if items[props.proplist].identifier == 'BoolProperty':
            col.prop(props, 'test_bool')
        row = col.row()


classes = [TEST_PG,
        TEST_PT_sub_01,
        ]


def register():
    for cls in classes:
        bpy.utils.register_class(cls)
    bpy.types.Scene.my_property_group= bpy.props.PointerProperty(
            type=TEST_PG)


def unregister():
    for cls in classes:
        bpy.utils.unregister_class(cls)
    del bpy.types.Scene.my_property_group

if __name__ == "__main__":
    register()
$\endgroup$
2
  • 1
    $\begingroup$ In blender API best practices it is recommended to use lower case for instance names and title or camel case for class names. For example, if adhered to MyPropertyGroup implies a class, and define bpy.types.Foo.my_property_group = PointerProperty(type=MyPropertyGroup) such that foo.my_property_group is an instance of the class. Similarly with scene and Scene object and Object window_manager and WindowManager etc. IMO the OP is having issues distinguishing between the two. Good answer nonetheless. $\endgroup$
    – batFINGER
    Commented Mar 10, 2021 at 9:55
  • 1
    $\begingroup$ @batFINGER Thank you for observation, updated to lower case for property group instantiation, removal & reference. $\endgroup$
    – Ratt
    Commented Mar 10, 2021 at 11:00

You must log in to answer this question.

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