1
$\begingroup$

I'm learning how to create UI panels in Blender. I have an IntProperty that I want to specify a certain number of sub-panels for. So far I here:

import bpy, sys, imp
from bpy.types import Operator, Panel, PropertyGroup, Menu
from bpy.props import *
from bpy.utils import register_class, unregister_class


class OBJECTTOOL_Settings(PropertyGroup):

    count: IntProperty(
        name = "Count",
        description="Number of objects to create",
        default = 1,
        min = 1,
        max = 6
        )

class OBJECTTOOL_PT_main_panel(Panel):
    bl_label = "Object Tools"
    bl_idname = "OBJECTTOOL_PT_main_panel"
    bl_space_type = "VIEW_3D"   
    bl_region_type = "UI"
    bl_category = "Object Tools"
    bl_context = "objectmode"

    def draw(self, context):
        layout = self.layout
        scene = context.scene
        objecttools = scene.objecttools
        row = layout.row()
        row.prop(objecttools, "count")

class OBJECTTOOL_PT_sub_panel(Panel):
    bl_label = "Sub Panel"
    bl_idname = "OBJECTTOOL_PT_sub_panel"
    bl_space_type = "VIEW_3D"   
    bl_region_type = "UI"
    bl_category = "Object Tools"
    bl_context = "objectmode"
    bl_parent_id = "OBJECTTOOL_PT_main_panel"

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

classes = (
    OBJECTTOOL_Settings,
    OBJECTTOOL_PT_main_panel,
    OBJECTTOOL_PT_sub_panel
)

def register():
    from bpy.utils import register_class
    for cls in classes:
        register_class(cls)

    bpy.types.Scene.objecttools = PointerProperty(type=OBJECTTOOL_Settings)

def unregister():
    from bpy.utils import unregister_class
    for cls in reversed(classes):
        unregister_class(cls)
    del bpy.types.Scene.objecttools


if __name__ == "__main__":
    register()

So of course the panel is being added by registering it, and it's being made a child by using the bl_parent_id tag.

How can I evaluate the value of the count: IntProperty I have setup, and have the same number of child panels created? I also want it to update the panels whenever the number changes.

(Eventually the plan is to have a menu in the sub panel that offers a menu of objects to create, then I can choose different objects in each panel, set parameters within the panel for that object, and then have a button at the top to create all objects according to the sub-panel selections.)

$\endgroup$
2
$\begingroup$

Dynamically register with python type

Can create a class using the type method. Code below makes a class name, makes a class with that name and sets the bl_idname class attribute to it as well. Note can pass draw methods et all in dictionary.

    id = f"OBJECTTOOL_PT_subx{n}"
    panel = type(id,
        (OBJECTTOOL_PT_sub_panel, Panel, ),
        {"bl_idname" : id}
        )    

Hence with a dynamic update on int property can register or unregister a subpanel classes on the fly. Used to be my go to method. It has since been my experience that quick scrubbing of a property can befuddle the registering and unregistering internals and start to fail and report missing RNA errors.

Getting the value of the scene property during restricted context when addons register is an issue if dynamically registering on fly with an update method.

Polling on the number

enter image description here

Instead for multi subpanels these days I go for a register them all (or in chunks as need be) approach and use a class property to poll against. The parent class poll will take care of any outside polling needs.

Add a class attribute number to each on creations, register them all and poll based on the number.

Another bonus is if the file is saved with 4 as the count prop, it will show 4 panels (when next run)

import bpy
from bpy.types import Operator, Panel, PropertyGroup, Menu
from bpy.props import IntProperty, PointerProperty
from bpy.utils import register_class, unregister_class


class OBJECTTOOL_PT_main_panel(Panel):
    bl_label = "Object Tools"
    bl_idname = "OBJECTTOOL_PT_main_panel"
    bl_space_type = "VIEW_3D"   
    bl_region_type = "UI"
    bl_category = "Object Tools"
    bl_context = "objectmode"

    def draw(self, context):
        layout = self.layout
        scene = context.scene
        objecttools = scene.objecttools
        row = layout.row()
        row.prop(objecttools, "count")

class OBJECTTOOL_PT_sub_panel(Panel):
    bl_label = "Sub Panel"
    bl_idname = "OBJECTTOOL_PT_sub_panel"
    bl_space_type = "VIEW_3D"   
    bl_region_type = "UI"
    bl_category = "Object Tools"
    bl_context = "objectmode"
    bl_parent_id = "OBJECTTOOL_PT_main_panel"

    @classmethod
    def poll(cls, context):
        ot = context.scene.objecttools
        return cls.count < ot.count

    def draw(self, context):
        layout = self.layout
        layout.label(text="SUBBY")

    
class OBJECTTOOL_Settings(PropertyGroup):

    count: IntProperty(
        name = "Count",
        description="Number of objects to create",
        default = 1,
        min = 1,
        max = 6,
        )        


classes = [
    OBJECTTOOL_Settings,
    OBJECTTOOL_PT_main_panel,
]

for i in range(5):
    id = f"OBJECTTOOL_PT_subx{i}"
    panel = type(id,
        (OBJECTTOOL_PT_sub_panel, Panel, ),
        {"bl_idname" : id,
         "count" : i}
        )
    classes.append(panel)

def register():
    from bpy.utils import register_class
    for cls in classes:
        register_class(cls)

    bpy.types.Scene.objecttools = PointerProperty(type=OBJECTTOOL_Settings)

def unregister():
    from bpy.utils import unregister_class
    for cls in reversed(classes):
        unregister_class(cls)
    del bpy.types.Scene.objecttools


if __name__ == "__main__":
    register()

Related

https://blender.stackexchange.com/a/179031/15543

https://blender.stackexchange.com/a/135374/15543

| improve this answer | |
$\endgroup$
  • $\begingroup$ Thank you so much! $\endgroup$ – DrewTNBD Jul 9 at 7:53
  • $\begingroup$ Actually I had a follow up - so I've got unique panels, but the panel class now has a propertygroup (with several EnumProperty definitions) and an operator. Would I need to dynamically register each of those too? $\endgroup$ – DrewTNBD Jul 9 at 9:22
  • 1
    $\begingroup$ Can't add bpy.props property definitions to a panel. (Wont work as expected). Dynamically registered panels posted as an example of how to make many based on one without a bunch of class defs that are mostly same. Not totally sure on what your aim is. Speculative note: A draw method can be defined on a property group. If still unclear perhaps post a new question linked back to this one for context. $\endgroup$ – batFINGER Jul 9 at 12:31
  • $\begingroup$ Cool, will do, cheers! $\endgroup$ – DrewTNBD Jul 9 at 14:49
  • $\begingroup$ Hey @batFINGER I've done as requested - blender.stackexchange.com/questions/185901/… $\endgroup$ – DrewTNBD Jul 10 at 10:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.