TransWikia.com

Facing Problem in drawing UI Previews Dynamic EnumProperty

Blender Asked by Rakesh choudhary on December 26, 2021

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:UsersADMINAppDataRoamingBlender FoundationBlender2.83scriptsaddonstest2_init_.py", line 31, in execute
    ".blend" + os.sep + "Object"), filepath=category + ".blend", filename=selected_preview)
    File "C:Program FilesBlender FoundationBlender 2.832.83scriptsmodulesbpyops.py", line 201, in call
    ret = op_call(self.idname_py(), None, kw)

RuntimeError: Error: ‘C:UsersADMINAppDataRoamingBlender FoundationBlender2.83scriptsaddonstest2BlendsObjects.blendObject’: 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:UsersADMINAppDataRoamingBlender
FoundationBlender2.83scriptsaddonstest2BlendsObjects.blendObject’:
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

One Answer

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()

Answered by AFWS on December 26, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP