4
$\begingroup$

One can make a sub-panel to be drawn inside a parent panel using bpy.types.Panel.bl_parent_id.

import bpy


class HelloWorldPanel(bpy.types.Panel):
    """Creates a Panel in the Scene properties window"""
    bl_label = "Hello World Panel"
    bl_idname = "OBJECT_PT_hello"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "scene"

    def draw(self, context):
        self.layout.label(text="Hello world!", icon='WORLD_DATA')


class HelloWorldSubPanel(bpy.types.Panel):
    """Creates a Panel in the Scene properties window"""
    bl_label = "Hello World Sub Panel"
    bl_idname = "OBJECT_PT_sub_hello"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_parent_id = "OBJECT_PT_hello"
    bl_context = "scene"

    def draw(self, context):
        self.layout.label(text="Hello world!", icon='WORLD_DATA')


def register():
    bpy.utils.register_class(HelloWorldPanel)
    bpy.utils.register_class(HelloWorldSubPanel)


if __name__ == "__main__":
    register()

enter image description here

I can check if the two panels are related with :

print(HelloWorldSubPanel.bl_parent_id == HelloWorldPanel.bl_idname)  # Returns True

But suppose I don't have access to the child class or don't want to hardcode the relationship test.

How would I know, without having access to the child panel class code, if the parent panel contains any children sub-panel ?

$\endgroup$

1 Answer 1

3
$\begingroup$

I could not find an attribute for this in API documentation. However, you can compare bl_idname with the bl_parent_id attribute of all panels to represent the hierarchy.

import bpy

class HelloWorldPanel:
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_category = "Tools"
    bl_options = {"DEFAULT_CLOSED"}


class HELLO_PT_World1(HelloWorldPanel, bpy.types.Panel):
    bl_idname = "HELLO_PT_World1"
    bl_label = "Panel 1"

    def draw(self, context):
        layout = self.layout
        #print (issubclass(self.__class__, HelloWorldPanel))
        layout.label(text="This is the main panel.")

class HELLO_PT_World2(HelloWorldPanel, bpy.types.Panel):
    bl_parent_id = "HELLO_PT_World1"
    bl_idname = "HELLO_PT_World2"
    bl_label = "Panel 2"

    def draw(self, context):
        layout = self.layout
        #print (issubclass(self.__class__, HELLO_PT_World1))
        layout.label(text="First Sub Panel of Panel 1.")

class HELLO_PT_World3(HelloWorldPanel, bpy.types.Panel):
    bl_parent_id = "HELLO_PT_World2"
    bl_idname = "HELLO_PT_World3"
    bl_label = "Panel 3"

    def draw(self, context):
        layout = self.layout
        layout.label(text="Second Sub Panel of Panel 1.")
        
classes = (
    # The order of registration must be parent panel first or loading errors will occur.Perhaps due to blender specifications, registration seems to be "by name," so class names may need to be created in order of name.
    HELLO_PT_World1,
    HELLO_PT_World2, 
    HELLO_PT_World3,
)

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

def unregister():
    for cls in classes:
        bpy.utils.unregister_class(cls)


if __name__ == "__main__":
    register()

    for idx, cls in enumerate(classes):
        for cls_rev in classes[idx+1:]:
            if hasattr(cls_rev, "bl_parent_id"):
                if cls.bl_idname == cls_rev.bl_parent_id:
                    print(cls.__name__, "is parent of", cls_rev.bl_idname)

Output:

HELLO_PT_World1 is parent of HELLO_PT_World2
HELLO_PT_World2 is parent of HELLO_PT_World3

The UI code comes from How to create a custom UI?

$\endgroup$
1
  • $\begingroup$ Yeah I was hoping not having to loop through all panel classes to find the relationships but it seems it isn't possible to get it directly through the API... This will do, thanks :) $\endgroup$
    – Gorgious
    Commented Jan 27, 2022 at 15:13

You must log in to answer this question.

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