When developing add-ons it is often necessary to give an ability to set a number of parameters that affect the whole add-on work to the user. For example, the user can specify a directory for saving/loading files, set some default variables or switch between add-on modes. Of course, the interface for setting such parameters can be placed in the add-on panel, but it is better to place it in a separate add-on preferences panel, which is located in the “Preferences” window under the add-on installation panel.
The main advantage of the add-on preferences is that they don’t reset when Blender restarts. The user does not need to configure the add-on preferences each time, it’s enough to set the necessary parameters once, personalizing the add-on for convenient work.
Let’s create an add-on and define a parameter, placing it in the add-on preferences panel.
At first create the simplest add-on, which adds a default cube to a scene by clicking a button in the N-panel of the 3D Viewport window.
Add-on code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
import bpy bl_info = { 'name': 'test', 'category': 'All', 'author': 'Korchiy', 'version': (0, 0, 1), 'blender': (2, 80, 0), 'location': '3D_Viewport window -> N-Panel > Test', 'description': 'Test' } class addCubeSample(bpy.types.Operator): bl_idname = 'mesh.add_cube_sample' bl_label = 'Add Cube' bl_options = {"REGISTER", "UNDO"} def execute(self, context): bpy.ops.mesh.primitive_cube_add() return {"FINISHED"} class addCubeSamplePanel(bpy.types.Panel): bl_idname = 'test.panel' bl_label = 'TEST' bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_category = 'TEST' def draw(self, context): self.layout.operator("mesh.add_cube_sample", icon='MESH_CUBE', text="Add Cube") def register(): bpy.utils.register_class(addCubeSample) bpy.utils.register_class(addCubeSamplePanel) def unregister(): bpy.utils.unregister_class(addCubeSamplePanel) bpy.utils.unregister_class(addCubeSample) if __name__ == '__main__': register() |
This “test” add-on works for Blender 2.8.
In this add-on we defined an operator class named “addCubeSample”, whith the identifier “mesh.add_cube_sample”.
In the “execute” method we call the system operator “mesh.primitive_cube_add”, which creates a default cube.
Creating the “addCubeSamplePanel” class we defined the “TEST” panel in the “3D Viewport” window for the user UI and placed the button for calling our operator “mesh.add_cube_sample” on it.
In the “register” and “unregister” functions we link the add-on to the Blender API.
We can install the add-on and execute it – by clicking the “Add Cube” button. A default cube will be added to the scene.
To add preferences to our add-on, we need to create a new class inheriting it from “bpy.types.AddonPreferences”:
1 2 |
class addCubeSamplePreferences(bpy.types.AddonPreferences): bl_idname = __name__ |
Our add-on is placed in a single file (module), so we must set the “bl_idname” identifier to the name of the add-on module “__name__”.
If you create preferences for a multi-file add-on, you need to specify the add-on package name instead of the module name:
1 2 |
class addCubeSamplePreferences(bpy.types.AddonPreferences): bl_idname = __package__ |
Let’s define a parameter that will affect the execution of our add-on — the Bevel modifier will be automatically added to the created cube if the user specifies this in the add-on preferences.
Parameters are created in the same way as for operator classes, using the types described in bpy.props: StringProperty, IntProperty, BoolProperty, etc.
Define a RadioButton switcher with two choices: “Add Bevel” – add a modifier to the cube, and “No Bevel” – don’t do that.
1 2 3 4 5 6 7 |
add_bevel: bpy.props.EnumProperty( items=[ ('bevel', 'Add bevel', '', '', 0), ('no_bevel', 'No Bevel', '', '', 1) ], default='no_bevel' ) |
“add_bevel” is the parameter name, the default value – not to add a modifier.
To show this parameter on the add-on preferences panel, we need to use the “draw” function. Drawing the user interface for the add-on preferences panel is done in the same way as for common UI panels.
1 2 3 4 5 |
def draw(self, context): layout = self.layout layout.label(text='Add bevel modifier:') row = layout.row() row.prop(self, 'add_bevel', expand=True) |
We added a “label” text field with the parameter description and the “add_bevel” parameter looks like a value switcher in this code.
The add-on preferences panel class must also be registered in the “register” function and unregistered in the “unregister” function.
To access the parameter from the add-on preferences in the operator class, we need to get it by specifying the add-on name and the parameter name. The following code returns the current value of the “add_bevel” property of our add-on:
1 |
bpy.context.preferences.addons['test'].preferences.add_bevel |
Add some code to the operator class “addCubeSample” for adding a Bevel modifier according to the “add_bevel” parameter value:
1 2 |
if context.preferences.addons['test'].preferences.add_bevel == 'bevel': bpy.ops.object.modifier_add(type='BEVEL') |
The final add-on code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
import bpy bl_info = { 'name': 'test', 'category': 'All', 'author': 'Korchiy', 'version': (0, 0, 1), 'blender': (2, 80, 0), 'location': '3D_Viewport window -> N-Panel > Test', 'description': 'Test' } class addCubeSample(bpy.types.Operator): bl_idname = 'mesh.add_cube_sample' bl_label = 'Add Cube' bl_options = {"REGISTER", "UNDO"} def execute(self, context): bpy.ops.mesh.primitive_cube_add() if context.preferences.addons['test'].preferences.add_bevel == 'bevel': bpy.ops.object.modifier_add(type='BEVEL') return {"FINISHED"} class addCubeSamplePanel(bpy.types.Panel): bl_idname = 'test.panel' bl_label = 'TEST' bl_space_type = 'VIEW_3D' bl_region_type = 'UI' bl_category = 'TEST' def draw(self, context): self.layout.operator("mesh.add_cube_sample", icon='MESH_CUBE', text="Add Cube") class addCubeSamplePreferences(bpy.types.AddonPreferences): bl_idname = __name__ add_bevel: bpy.props.EnumProperty( items=[ ('bevel', 'Add bevel', '', '', 0), ('no_bevel', 'No bevel', '', '', 1) ], default='no_bevel' ) def draw(self, context): layout = self.layout layout.label(text='Add bevel modifier:') row = layout.row() row.prop(self, 'add_bevel', expand=True) def register(): bpy.utils.register_class(addCubeSample) bpy.utils.register_class(addCubeSamplePanel) bpy.utils.register_class(addCubeSamplePreferences) def unregister(): bpy.utils.unregister_class(addCubeSamplePreferences) bpy.utils.unregister_class(addCubeSamplePanel) bpy.utils.unregister_class(addCubeSample) if __name__ == '__main__': register() |
Install the add-on. Now an additional “Preferences” panel appears under the add-on panel.
If the user sets the switcher to the “Add Bevel” position and saves preferences by clicking the “Save Preferences” button, the default cube created with our add-on will be added to a scene with the “Bevel” modifier by default.
This doesn’t seem to work anymore, whenever I try to add a cube I get the following error message:
The blender version I’m using is 3.2, but neither 3.3 or even 2.81 worked, is there a fix to this?
Do not execute this code from the Blender Text Editor area. Create a separate .py file, copy this code to it, and install the add-on from this file by pressing the “install” button in the Blender Preferences area. When you do this – Blender installs the code as an add-on.
If you try to execute the code from the Text Editor area, Blender don’t create an add-on, it just executes the code. So it can’t address by the [‘test’] key and trows an error.
Install this code from the separate file, and it will work.
I had to change context.preferences.addons[‘test’] and change ‘test wo quotes ‘to my file name that I saved and then installed into blender… to get it to work. so ‘test’ became ‘Addon preferences’. from the filename Addon preferences.py
You can use __name__ except “test” or any other static string name.