0
$\begingroup$

This is how I sofar define a class for a panel inside the tool shelve.

class ObjectLayer(bpy.types.Panel):
    bl_label = "ObjectLayer"
    bl_idname = "ObjectLayer"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'
    bl_category = "Claas"

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

        obj = context.object

        row = layout.row()
        row.prop(obj , "layers")

Then I got this amazing script in how to show the modifier stack in the tool bar but it uses a very different format for declaring a class

import bpy
from bpy.types import Menu, Panel, UIList
from bl_ui.properties_data_modifier import DATA_PT_modifiers as PT_MOD

@classmethod
def poll(cls, context):
    return (context.object is not None)

def make_panel(name, poll, funcs):
    overwrites = {
        "bl_space_type": "VIEW_3D",
        "bl_region_type": "TOOLS",
        "bl_label": "Test",
        "bl_context": "objectmode",
        "bl_category": "Test",
        "poll": poll,
        "draw": getattr(funcs, "draw")
    }

    for f in dir(funcs):
        if f.isupper():
            overwrites[f] = getattr(funcs, f)

    return type(name, (Panel,), overwrites)

RigPanel = make_panel("OpenStudioAddRigPanel", poll, funcs=PT_MOD)

def register(): bpy.utils.register_class(RigPanel)
def unregister(): bpy.utils.unregister_class(RigPanel)
if __name__ == "__main__": register()

This is what I tried:

import bpy
from bpy.types import Menu, Panel, UIList
from bl_ui.properties_data_modifier import DATA_PT_modifiers as PT_MOD


class ObjectLayer(bpy.types.Panel):
bl_label = "ObjectLayer"
bl_idname = "ObjectLayer"
bl_space_type = 'VIEW_3D'
bl_region_type = 'TOOLS'
bl_category = "Claas"


def poll(cls, context):
return (context.object is not None)


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

ob = context.object

layout.operator_menu_enum("object.modifier_add", "type")

for md in ob.modifiers:
    box = layout.template_modifier(md)
    if box:
        # match enum type to our functions, avoids a lookup table.
        getattr(self, md.type)(box, ob, md)


def make_panel(name, poll, draw, funcs):
overwrites = {
    "bl_space_type": "VIEW_3D",
    "bl_region_type": "TOOLS",
    "bl_label": "Test",
    "bl_context": "objectmode",
    "bl_category": "Test",
    "poll": poll,
    "draw": draw
}

for f in dir(funcs):
    if f.isupper():
        overwrites[f] = getattr(funcs, f)

return type(name, (Panel,), overwrites)

RigPanel = make_panel("OpenStudioAddRigPanel", poll, draw, funcs=PT_MOD)

def register():
bpy.utils.register_class(ObjectLayer)

def unregister():
bpy.utils.register_class(ObjectLayer)

if __name__ == "__main__":
register()

Traceback (most recent call last): File "C:\Users\info\Desktop\untitled.blend\Text", line 58, in File "C:\Users\info\Desktop\untitled.blend\Text", line 52, in register AttributeError: expected Panel, ObjectLayer class to have an "draw" attribute

$\endgroup$
0

1 Answer 1

2
$\begingroup$

Use the regular class definition scheme as shown in the TextEditor Python Templates -- unless you have a good reason to use a class Factory.

As Sambler shows in the new answer to the previous question: You can do this much simpler with standard class definitions -- the use of the "class Factory" was not appropriate in this scenario because it wasn't the least complicated solution.


However, to answer this question anyway; the make_panel function is what we might call a "class Factory".

Positive

  • It generates unique classes on the fly, requiring little code to individualize each class. Especially useful if you need many classes which differ only in small but important ways.
  • This avoids explicitly writing the full class out in code for every class if you just need to change a couple of lines or functions per class.

negative

  • The downside to a class factory is it becomes tricky to reason about the code, especially for newcomers. If you don't know how to introspect a class it becomes a bit of a black-box.
  • classes generated this way must be registered with bpy.utils.register_class(...)
    • register_module(__name__) won't find these classes automatically.

How to use such things correctly is better discussed on a programming QA like StackOverflow. See this question / answer " How can I dynamically create derived classes from a base class " . If that question is over the top of your head, probably wait till you get more Python experience before using the code.

$\endgroup$

You must log in to answer this question.

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