2
$\begingroup$

In the Blender preferences I would like to add paths to external resources, but I don't really know how to do it, I am aware that I can register a StringProperty property this way in the preferences:

class MyAddonPreferences(bpy.types.AddonPreferences):    

    bl_idname = __name__
    
    path: bpy.props.StringProperty(name="PATH",subtype='DIR_PATH',description = '')

So I can access the path chosen by the user in this way:

preferences = bpy.context.preferences.addons[__name__].preferences
path = preferences.path

However, this is limiting if the resources can be multiple and chosen by the user. For example I would like to be able to add some other path of your choice with an "Add" or "Remove" button. Basically I'm trying to memorize some path in the addon preferences. I have no idea what the best way to do it is

$\endgroup$
2
  • $\begingroup$ Hello Gorgious, I think you are partly right, the answer of @brockmann is very consistent with my question, while the one you pointed out to me is less consistent with my question, I think brockman's answer will be useful for many people as it is very specifies on this specific question. $\endgroup$
    – Noob Cat
    Apr 25, 2021 at 21:48
  • 2
    $\begingroup$ Agreed, I proposed the duplicate vote before the answer was posted. Cheers $\endgroup$
    – Gorgious
    Apr 26, 2021 at 7:47

1 Answer 1

5
$\begingroup$

You would have to declare a CollectionProperty and assign its type to a previously declared PropertyGroup to hold multiple generic entries. Demo based on the code provided in the docs:

enter image description here

bl_info = {
    "name": "Example Add-on Preferences",
    "author": "Your Name Here",
    "version": (1, 0),
    "blender": (2, 80, 0),
    "location": "",
    "description": "Example Add-on",
    "warning": "",
    "doc_url": "",
    "tracker_url": "",
    "category": "Development",
}


import bpy
from bpy.types import Operator, AddonPreferences, PropertyGroup
from bpy.props import StringProperty, CollectionProperty


class CUSTOM_PG_filepaths(PropertyGroup):
    # name: bpy.props.StringProperty()
    path: bpy.props.StringProperty(subtype='FILE_PATH')
    display: bpy.props.BoolProperty()

class ExampleAddonPreferences(AddonPreferences):
    # this must match the add-on name, use '__package__'
    # when defining this in a submodule of a python package.
    bl_idname = __name__

    filepaths: CollectionProperty(
        name="File paths",
        type=CUSTOM_PG_filepaths)

    def draw(self, context):
        layout = self.layout
        layout.label(text="This is a preferences view for our add-on")
        for i in self.filepaths:
            if i.display == True:
                layout.prop(i, "path")

filepath_list = {
    "geo": "//asset.obj",
    "anim": "//asset.fbx",
    "render": "//asset.exr"
}

def register():
    bpy.utils.register_class(CUSTOM_PG_filepaths)
    bpy.utils.register_class(ExampleAddonPreferences)
    
    paths = bpy.context.preferences.addons[__name__].preferences.filepaths
    if not paths:
        for key, value in filepath_list.items():
            item = paths.add()
            item.name = key
            item.path = value
            item.display = True


def unregister():
    bpy.utils.unregister_class(ExampleAddonPreferences)
    bpy.utils.unregister_class(CUSTOM_PG_filepaths)

If you'd like to allow the user adding an arbitrary amount of filepaths, you can display the contents of the PropertyGroup in a custom UIList which will look like the material list, see:

Create an interface which is similar to the material list box


Alternatively you can just add a simple operator to add a new item:

enter image description here

class OBJECT_OT_addon_prefs_example(Operator):
    """Display example preferences"""
    bl_idname = "object.addon_prefs_example"
    bl_label = "Add-on Preferences Example"
    bl_options = {'REGISTER', 'UNDO'}

    def execute(self, context):
        preferences = context.preferences
        addon_prefs = preferences.addons[__name__].preferences
        item = addon_prefs.filepaths.add()
        item.display = True
            
        self.report({'INFO'}, "New Filepath added")
        return {'FINISHED'}
$\endgroup$
1
  • $\begingroup$ Great solution, I had in mind to use CollectionProperty, but I was not sure about it as I thought it would not remain stored, instead, by saving the preferences, all the added paths are saved in the preferences and therefore always available. I would like to give more points for this answer, it really was very helpful and coherent to my question. $\endgroup$
    – Noob Cat
    Apr 25, 2021 at 21:45

You must log in to answer this question.

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