1
$\begingroup$

I am making custom icons for my Blender add-on. I read the bpy.utils.previews.ImagePreviewCollection already. I tried code and set the __file__ to bpy.context.space_data.text.filepath it works very well.

But, when I add the codes to my add-on file, it doesn't show the icon. Here is the code:


#Add-on info
bl_info = {
    "name": "Shader",
    "author": "me",
    "version": (1, 0),
    "blender": (2, 92, 0),
    "location": "View3D > Toolbar > Shader",
    "description": "Add shaders to your object",
    "category": "3D View",
}



import os
import bpy
from bpy.types import Operator
from bpy.props import StringProperty, IntProperty
from bpy.types import Panel



# Main panel for adding colour to object
class ShaderPanel(bpy.types.Panel):
    bl_label = "Shader"
    bl_idname = "ShaderPanel"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'Shader'
    
        
    def draw(self, context):
        layout = self.layout
        pcoll = preview_collections["main"]
        row = layout.row()
        my_icon = pcoll["my_icon"]
        your_icon = pcoll["your_icon"]
        
        row.operator("render.render", icon_value=your_icon.icon_id)
        row.operator("render.render", icon_value=my_icon.icon_id)
        
        

classes = [ShaderPanel]

preview_collections = {}


def register():
    from bpy.types import WindowManager
    from bpy.props import (
        StringProperty,
        EnumProperty,
    )
    
    ############ Custom Icons ############
    import bpy.utils.previews
    pcoll = bpy.utils.previews.new()

    # path to the folder where the icon is
    # the path is calculated relative to this py file inside the addon folder
    my_icons_dir = os.path.join(os.path.dirname(__file__), "icons")

    # load a preview thumbnail of a file and store in the previews collection
    pcoll.load("my_icon", os.path.join(my_icons_dir, "icon.png"), 'IMAGE')
    pcoll.load("your_icon", os.path.join(my_icons_dir, "icon1.png"), 'IMAGE')

    preview_collections["main"] = pcoll
    #######################################

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

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

    for cls in classes:
        bpy.utils.unregister_class(cls)
        
        
if __name__ == "__main__":
    __file__ = bpy.context.space_data.text.filepath
    register()

I did not get error, but it doesn't show icon. Here is what I got: enter image description here

Here is the folders and files/images location:

enter image description here

Please help me, I already read many common questions but that doesn't solve my problem.

$\endgroup$
5
  • $\begingroup$ Hello ! While it's nice to provide a working code example, could you restrict it to the part that's responsible for drawing the UI so it's easier to pinpoint it ? Thanks in advance :) $\endgroup$
    – Gorgious
    Jan 24, 2022 at 6:40
  • $\begingroup$ @Gorgious I don't understand what you want me to do. Do you mean there is too many codes on it that uneasy too read? $\endgroup$
    – userN08
    Jan 24, 2022 at 6:43
  • $\begingroup$ Do you know why my code doesn't work, but the code in documentation works? $\endgroup$
    – userN08
    Jan 24, 2022 at 6:45
  • 1
    $\begingroup$ Yes, I'm saying it would take me 10 mins to read through all of your addon code to try and find out what is wrong, while if you isolated the part that's responsible for drawing the UI in the panel, that time would be much faster $\endgroup$
    – Gorgious
    Jan 24, 2022 at 6:48
  • $\begingroup$ @Gorgious Now, I edited. I already put those unrelated codes away and pls see my codes and find what's the problem. thanks $\endgroup$
    – userN08
    Jan 24, 2022 at 6:56

1 Answer 1

3
$\begingroup$

Your path to resources is wrong:

my_icons_dir = os.path.join(os.path.dirname(__file__), "icons")

See template ui_previews_custom_icon.py:

IMPORTANT NOTE: You need to replace the image path with a real existing one. For distributable scripts, it is recommended to place the icons inside the addon folder and access it relative to the py script file for portability

For this we can use bpy.utils.user_resource(resource_type, path='', create=False) link

Script:

#Add-on info
bl_info = {
    "name": "Shader",
    "author": "me",
    "version": (1, 0),
    "blender": (2, 92, 0),
    "location": "View3D > Toolbar > Shader",
    "description": "Add shaders to your object",
    "category": "3D View",
}

import os
import bpy
from bpy.types import Operator
from bpy.props import StringProperty, IntProperty
from bpy.types import Panel

# Main panel for adding colour to object
class SHADER_PT_PANEL(bpy.types.Panel):
    bl_label = "Shader"
    bl_idname = "SHADER_PT_PANEL"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'Shader'
    
    def draw(self, context):
        layout = self.layout
        pcoll = preview_collections["main"]
        row = layout.row()
        my_icon = pcoll["my_icon"]
        your_icon = pcoll["your_icon"]
        
        row.operator("render.render", icon_value=your_icon.icon_id)
        row.operator("render.render", icon_value=my_icon.icon_id)
        

classes = [SHADER_PT_PANEL]
preview_collections = {}


def register():
    from bpy.types import WindowManager
    from bpy.props import (
        StringProperty,
        EnumProperty,
    )
    
    ############ Custom Icons ############
    import bpy.utils.previews
    pcoll = bpy.utils.previews.new()

    # path to the folder where the icon is
    # the path is calculated relative to this py file inside the addon folder
###    my_icons_dir = os.path.join(os.path.dirname(__file__), "icons")

    # this path is for installed addons in user_resources ; doesn´t work as script , for script you need a path to your resources
    my_icons_dir = bpy.utils.user_resource('SCRIPTS', path='addons\Shader' , create=False)   # assuming addon folder is called 'Shader'

    # load a preview thumbnail of a file and store in the previews collection
    pcoll.load("my_icon", os.path.join(my_icons_dir, "icon.png"), 'IMAGE')              # assuming '*.png' is inside folder 'Shader'
    pcoll.load("your_icon", os.path.join(my_icons_dir, "icon1.png"), 'IMAGE')

    preview_collections["main"] = pcoll
    #######################################

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

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

    for cls in classes:
        bpy.utils.unregister_class(cls)
        
if __name__ == "__main__":
    __file__ = bpy.context.space_data.text.filepath
    register()
$\endgroup$
4
  • $\begingroup$ according to your answer, my code should change to my_icons_dir = bpy.utils.user_resource('SCRIPTS', path='Shader Adder\icons' , create=False) since my path is \Documents\Scripting\Blender\Shader Adder\icons but this doesn't work. Please tell me what is the problem, thx $\endgroup$
    – userN08
    Jan 24, 2022 at 12:37
  • $\begingroup$ Another question about your answer, you tell me to see template ui_previews_custom_icon.py, but my code is copy from it. You also note that I need to replace the image path with a real existing one, so my code has: __file__ = bpy.context.space_data.text.filepath . $\endgroup$
    – userN08
    Jan 24, 2022 at 12:41
  • 1
    $\begingroup$ print(bpy.utils.user_resource('SCRIPTS')) returns the folder where installed (!) user addons are saved in a subfolder called addons. For this path='addons\Shader Adder\icons'if addonfolder is Shader Adder and icons in subfolder icons. bpy.context.space_data.text.filepath is the path from where a file was loaded into the text editor. $\endgroup$
    – relaxed
    Jan 24, 2022 at 14:43
  • $\begingroup$ Thank you very much for answering. I understand now. $\endgroup$
    – userN08
    Jan 24, 2022 at 15:58

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.