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$
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$

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.