I'm developing a Blender Addon which consists of multiple Modules. Each module adds a unique section with unique operators to a custom created panel. I want the user to be able to load and unload the modules in the Addon Preferences by checking or unchecking a box next to the corresponding name of the module. All the modules are written in seperate files. I want the Addon to present a list of all available "plugins" (modules) in the Addon Preferences by scanning a specific directory where all module files reside. Also, the enabled modules should be written to the User Preferences, so that after closing and reopening Blender everything stays the same.

My idea to achieve the described aim was to create a CollectionProperty where all the scanned modules are stored. When activated, the modules are imported and then loaded by executing the register() respectively unregister() function. However I'm not sure where to put this... in the __init_.py? And how can I permanently store the information? I try to avoid writing it to a custom configuration file.

EDIT: I started writing and got the basic funcionality working. Here is my code so far:

import bpy
import os
import importlib
import sys

bl_info = {
    'name': 'Addon',
    'category': 'User'
}

sys.path.append("C:/modules/")


# Scan directory for modules and append to a list
def get_available_modules():
    available_modules = []
    for module in os.listdir('C:/modules/'):
        if os.path.isfile(os.path.join('C:/modules/', module)):
            available_modules.append(module.replace('.py', ''))
    return available_modules


# PropertyGroup for one module
class Module(bpy.types.PropertyGroup):
    name = bpy.props.StringProperty(
        default=''
    )

    enabled = bpy.props.BoolProperty(
        default=False
    )


class RefreshModules(bpy.types.Operator):
    bl_idname = "modules.refresh"
    bl_label = "Refresh Modules"

    def execute(self, context):
        available_modules = get_available_modules()
        for module in available_modules:
            if bpy.context.scene.Modules.find(module) == -1:
                newModule = bpy.context.scene.Modules.add()
                newModule.name = module
                newModule.enabled = False
        for module in bpy.context.scene.Modules:
            if module.enabled:
                    importmodule = importlib.import_module(module.name)
                    importmodule.register()
            if not module.enabled:
                    importmodule = importlib.import_module(module.name)
                    importmodule.unregister()

        return {'FINISHED'}


# AddonPreferences
class MyAddonPreferences(bpy.types.AddonPreferences):
    bl_idname = __name__

    # draw a list with available modules and checkboxes for loading and unloading
    def draw(self, context):
        layout = self.layout
        col = layout.column()
        col.operator("modules.refresh", text="Refresh Modules", icon='FILE_REFRESH')
        for module in bpy.context.scene.Modules:
            col.label(module.name)
            col.prop(bpy.context.scene.Modules[module.name], "enabled")


def register():
    bpy.utils.register_class(MyAddonPreferences)
    bpy.utils.register_class(Module)
    bpy.utils.register_class(RefreshModules)
    bpy.types.Scene.Modules = bpy.props.CollectionProperty(type=Module)


def unregister():
    bpy.utils.unregister_class(MyAddonPreferences)
    bpy.utils.unregister_class(Module)
    bpy.utils.unregister_class(RefreshModules)
    del bpy.types.Scene.Modules

I have the following issues with my code, hopefully someone can help me with that:

  • in the RefreshModules class, for unregistering modules I first import them to get the class object, I think this can be done differently
  • Enabled or disabled modules are not stored in AddonPreferences, I guess I somehow need to bring the PropertyGroup into the AddonPreferences Class
  • the RefreshModules Operator fails when reloading the addon with F8:

File "C:\addon\addon.py", line 48, in execute importmodule.register() File "C:/modules\moduleone.py", line 68, in register bpy.utils.register_module(name) File "C:\Program Files\Blender Foundation\Blender\2.79\scripts\modules\bpy\uti ls__init__.py", line 685, in register_module raise Exception("register_module(%r): defines no classes" % module) Exception: register_module('moduleone'): defines no classes

However, on first load, this works fine.

Thanks for help in advance

  • 2
    Blender does this for addons by importing the modules selected as addons from the addons folder. Pretty much use the same as that, with modules in your addons folder.. btw. I have done something similar for numerous addons. An example image Re your question: please consider making some attempt at your described aim and not just a list of I wants post some code or links to. – batFINGER Mar 18 at 20:07

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Browse other questions tagged or ask your own question.