0
$\begingroup$

I am trying to Draw Dynamic Enum property and I started using a one of the templates provided with the blender.

What I am trying to do: I have a Folder Test 2 in which I have 2 Folders -

  1. Blends
  2. Icons

and a __ init __.py in which I am drawing Enum.

I want to import icons from the Icons folder and for each icon, the object should be appended from the Objects.blend file present in the Blends folder.

my icons are cube, sphere, plane, Suzanne...., A cube should be appended when I select cube icon and hit add button, and similarly, the sphere should be appended when clicked on sphere icon (I have used cube, sphere, etc objects as an example, in future I will be replacing these object with the actual object I want to import).The object to be imported and icon for it has exactly the same name

If anyone wants to try complete file here is the link - To get files, Click here

This is .blend file -

So, this is my__ init __.py file -

bl_info = {
    "name": "Add Object",
    "author": "Rakesh",
    "version": (1, 0),
    "blender": (2, 83, 0),
    "location": "View3D > Add > Mesh > New Object",
    "description": "Adds a new Mesh Object",
    "warning": "",
    "category": "Add Mesh",
}
import bpy
import os
from bpy.types import (
    Operator,
    Panel,
    PropertyGroup,
)
from bpy.props import *
import bpy.utils.previews
from bpy.types import WindowManager

class Object_OT_AddButton(Operator):
    bl_idname = "add.object"
    bl_label = "Add Object"

    def execute(self, context):
        selected_preview = bpy.data.window_managers["WinMan"].my_previews
        category = context.scene.my_tool.cat

        bpy.ops.wm.append(directory=os.path.join(os.path.dirname(__file__), "Blends" + os.sep + category +
                                                 ".blend" + os.sep + "Object"), filepath=category + ".blend", filename=selected_preview)
        return{'FINISHED'}


def update_category(self, context):
    enum_previews_from_directory_items(self, context)


class Categories(PropertyGroup):
    mesh_options = [
        ("Objects", "Objects", '', 0),

    ]

    cat = bpy.props.EnumProperty(

        items=mesh_options,
        description="Select a Category",
        default="Objects",
        update=update_category
    )


def enum_previews_from_directory_items(self, context):

    category = context.scene.my_tool.cat
    # Icons Directory

    directory = os.path.join(os.path.dirname(
       __file__), "Icons" + os.sep + category)

    enum_items = []

    if context is None:
        return enum_items

    wm = context.window_manager
    directory = wm.my_previews_dir

    # Get the preview collection (defined in register func).
    pcoll = preview_collections["main"]

    if directory == pcoll.my_previews_dir:
        return pcoll.my_previews

    print("Scanning directory: %s" % directory)

    if directory and os.path.exists(directory):
        # Scan the directory for png files
        image_paths = []
        for fn in os.listdir(directory):
            if fn.lower().endswith(""):
                image_paths.append(fn)

        for i, name in enumerate(image_paths):
            # generates a thumbnail preview for a file.
            filepath = os.path.join(directory, name)
            icon = pcoll.get(name)
            if filepath in pcoll:
                enum_items.append((name, name, "", pcoll[filepath].icon_id, i))
            else:
                thumb = pcoll.load(filepath, filepath, 'IMAGE')
                enum_items.append((name, name, "", thumb.icon_id, i))

    pcoll.my_previews = enum_items
    pcoll.my_previews_dir = directory
    return pcoll.my_previews


class PreviewsExamplePanel(Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "Add object Panel"
    bl_idname = "OBJECT_PT_previews"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"

    def draw(self, context):
        layout = self.layout
        wm = context.window_manager
        scene = context.scene
        mytool = scene.my_tool

        col = layout.column()
        col.prop(context.scene.my_tool, "cat", text="Category")

        row = layout.row()
        row.template_icon_view(wm, "my_previews", show_labels=True)

        row = layout.row()
        row.operator("add.object", icon="RESTRICT_RENDER_OFF", text="Add")


# We can store multiple preview collections here,
# however in this example we only store "main"
preview_collections = {}


def register():
    from bpy.types import WindowManager
    from bpy.props import (
        StringProperty,
        EnumProperty,
    )

    WindowManager.my_previews_dir = StringProperty(
        name="Folder Path",
        subtype='DIR_PATH',
        default=""
    )

    WindowManager.my_previews = EnumProperty(
        items=enum_previews_from_directory_items,
    )

    import bpy.utils.previews
    pcoll = bpy.utils.previews.new()
    pcoll.my_previews_dir = ""
    pcoll.my_previews = ()

    preview_collections["main"] = pcoll

    bpy.utils.register_class(Object_OT_AddButton)
    bpy.utils.register_class(Categories)
    bpy.types.Scene.my_tool = PointerProperty(type=Categories)
    bpy.utils.register_class(PreviewsExamplePanel)


def unregister():
    from bpy.types import WindowManager

    del WindowManager.my_previews

    for pcoll in preview_collections.values():
        bpy.utils.previews.remove(pcoll)
    preview_collections.clear()

    bpy.utils.unregister_class(Object_OT_AddButton)
    bpy.utils.unregister_class(Categories)
    del bpy.types.Scene.my_tool
    bpy.utils.unregister_class(PreviewsExamplePanel)


if __name__ == "__main__":
    register()

Issues I am facing -

  1. Error: Traceback (most recent call last): File "C:\Users\ADMIN\AppData\Roaming\Blender Foundation\Blender\2.83\scripts\addons\test2_init_.py", line 31, in execute ".blend" + os.sep + "Object"), filepath=category + ".blend", filename=selected_preview) File "C:\Program Files\Blender Foundation\Blender 2.83\2.83\scripts\modules\bpy\ops.py", line 201, in call ret = op_call(self.idname_py(), None, kw)

RuntimeError: Error: 'C:\Users\ADMIN\AppData\Roaming\Blender Foundation\Blender\2.83\scripts\addons\test2\Blends\Objects.blend\Object': nothing indicated

location: < unknown location >:-1

  1. The issue shown above is not reported normally, I mean by this is when I press the button this error is shown, otherwise no errors are shown.

This is what my panel looks like -

Screenshot of Panel

when I click that add button I get that error, the reason of the error what I believe is some thing is wrong in importing icons as icons are not imported and without selecting any icon i am clicking add and that gives the error -

RuntimeError: Error: 'C:\Users\ADMIN\AppData\Roaming\Blender Foundation\Blender\2.83\scripts\addons\test2\Blends\Objects.blend\Object': nothing indicated


I am trying to achieve this type of Panel, In this panel, a particle system is added but I don't want any particle system I just want the object to be appended to the scene when the icon from the dynamic enum is clicked.

Reference Image -

Real Grass add-on Panel

$\endgroup$
  • 2
    $\begingroup$ category = context.scene.object.cat suggests some pointer property object is set on Scene type to propertygroup above. But It isn't. $\endgroup$ – batFINGER Jul 24 at 10:08
  • 2
    $\begingroup$ Look in system concolse.... does it give a reason it does not register, could it be that the Categories class hasn't been registered? Please make some effort to debug code, or look for answers, before posting each error message. $\endgroup$ – batFINGER Jul 24 at 11:28
  • 5
    $\begingroup$ Please, please, please, please, please take some time and look before posting each error message. . What did you call the pointer property on the scene? $\endgroup$ – batFINGER Jul 24 at 12:22
  • 2
    $\begingroup$ bpy.types.Scene.object = PointerProperty(... Then the scene will have scene.object.cat consult the documentation Was an absolute beginner at one stage too. May sound counter-intuitive but consider disconnecting from net for an hour or so and nut these things out. Coding is logic. eg Scene has no object property, when you think about it you don't really need someone telling you what this means. $\endgroup$ – batFINGER Jul 24 at 12:46
  • 1
    $\begingroup$ It might help to upload the blender file: blend-exchange.giantcowfilms.com $\endgroup$ – ElliotThomas Jul 30 at 18:26
1
+50
$\begingroup$

Looks like it was your file path causing issues. One thing I noticed, it doesn't show under addons ,but didn't take time to figure out why.

enter image description here

bl_info = {
    "name": "Add Object",
    "author": "Rakesh",
    "version": (1, 0, 0),
    "blender": (2, 83, 0),
    "location": "View3D > Add > Mesh > New Object",
    "description": "Adds a new Mesh Object",
    "warning": "",
    "category": "Add Mesh",
}


import bpy, os
from bpy.types import (
    Operator,
    Panel,
    PropertyGroup,
)
from bpy.props import *
import bpy.utils.previews
from bpy.types import WindowManager


class Object_OT_AddButton(Operator):
    bl_idname = "add.object"
    bl_label = "Add Object"

    def execute(self, context):
        selected_preview = context.window_manager.my_previews        
                
        category = context.scene.my_tool.cat
                                                         
        user = bpy.utils.user_resource('SCRIPTS', "addons\\test2\\")
        
        preview_no_ext = selected_preview.split('.')[0]        
        blendpath = category + ".blend"                                                                                                  
        blenddir = os.path.join(user + "Blends" + os.sep + category + ".blend" + os.sep + "Object\\")
          
        bpy.ops.wm.append(directory=blenddir, filepath=blendpath, filename=preview_no_ext)
        
                
        return{'FINISHED'}


def update_category(self, context):
    enum_previews_from_directory_items(self, context)


class Categories(PropertyGroup):
    mesh_options = [
        ("Objects", "Objects", '', 0),

    ]

    cat: bpy.props.EnumProperty(

        items=mesh_options,
        description="Select a Category",
        default="Objects",
        update=update_category
    )


def enum_previews_from_directory_items(self, context):

    category = context.scene.my_tool.cat
    
    #Extensions
    extensions = ('.jpeg', '.jpg', '.png')

    # Icons Directory    
    directory = bpy.utils.user_resource('SCRIPTS', "addons\\test2\\Icons\\")
    
    enum_items = []

    if context is None:
        return enum_items

    pcoll = preview_collections["main"]

    if directory == pcoll.my_previews_dir:
        return pcoll.my_previews

    if directory and os.path.exists(directory):
        # Scan the directory for png files
        image_paths = []
        for fn in os.listdir(directory):
            if fn.lower().endswith(extensions):
                image_paths.append(fn)

        for i, name in enumerate(image_paths):
            # generates a thumbnail preview for a file.
            filepath = os.path.join(directory, name)
            icon = pcoll.get(name)
            if filepath in pcoll:
                enum_items.append((name, name, "", pcoll[filepath].icon_id, i))
            else:
                thumb = pcoll.load(filepath, filepath, 'IMAGE')
                enum_items.append((name, name, "", thumb.icon_id, i))

    pcoll.my_previews = enum_items
    pcoll.my_previews_dir = directory
    return pcoll.my_previews


class PreviewsExamplePanel(Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "Add object Panel"
    bl_idname = "OBJECT_PT_previews"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"

    def draw(self, context):
        layout = self.layout
        wm = context.window_manager
        scene = context.scene
        mytool = scene.my_tool

        col = layout.column()
        col.prop(context.scene.my_tool, "cat", text="Category")

        row = layout.row()
        row.template_icon_view(wm, "my_previews", show_labels=True)

        row = layout.row()
        row.operator("add.object", icon="RESTRICT_RENDER_OFF", text="Add")


# We can store multiple preview collections here,
# however in this example we only store "main"
preview_collections = {}


def register():

    WindowManager.my_previews_dir = StringProperty(
        name="Folder Path",
        subtype='DIR_PATH',
        default=""
    )

    WindowManager.my_previews = EnumProperty(
        items=enum_previews_from_directory_items,
    )

    pcoll = bpy.utils.previews.new()
    pcoll.my_previews_dir = ""
    pcoll.my_previews = ()

    preview_collections["main"] = pcoll

    bpy.utils.register_class(Object_OT_AddButton)
    bpy.utils.register_class(Categories)
    bpy.types.Scene.my_tool = PointerProperty(type=Categories)
    bpy.utils.register_class(PreviewsExamplePanel)


def unregister():

    del WindowManager.my_previews

    for pcoll in preview_collections.values():
        bpy.utils.previews.remove(pcoll)
    preview_collections.clear()

    bpy.utils.unregister_class(Object_OT_AddButton)
    bpy.utils.unregister_class(Categories)
    del bpy.types.Scene.my_tool
    bpy.utils.unregister_class(PreviewsExamplePanel)


if __name__ == "__main__":
    register()
| improve this answer | |
$\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.