4
$\begingroup$

I'm writing an add-on and have a float property which drives the thickness attribute of a solidify modifier for the selected object. Currently, the float property displays the last value assigned by the user using that property. Instead, when the user selects an object, I'd like the float property to display the value for that object's solidify modifier.

I've written this function but from what I've read, this won't work anywhere within the draw or poll functions for the panel.

def SyncThickness():
    myprops = bpy.data.scenes["Scene"].my_properties
    if len(bpy.context.selected_objects) >=1:
        myprops.thickness_float = bpy.context.selected_objects[0].modifiers["Solidify"].thickness
    else:
        myprops.thickness_float = 0

Is there anyway to call this function whenever a different object is selected? Or is a different approach required?

Thanks

Chris

$\endgroup$

2 Answers 2

4
$\begingroup$

Use Application Handlers (bpy.app.handlers)

import bpy
from bpy.app.handlers import persistent

@persistent
def update_function(dummy):
    print("run...")
    # when select a object or depsgraph data changed, it will run

bpy.app.handlers.depsgraph_update_post.append(update_function)

API link: https://docs.blender.org/api/current/bpy.app.handlers.html?highlight=load_post#bpy.app.handlers.load_post

$\endgroup$
1
  • $\begingroup$ Works perfectly, thank you! $\endgroup$ May 7, 2022 at 9:55
3
$\begingroup$

You could just utilize the modifier property directly:

import bpy


class VIEW3D_PT_test(bpy.types.Panel):
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = "Test Panel"
    bl_idname = "VIEW3D_PT_test_panel_1"
    bl_label = "Test Panel 1"


    def draw(self, context):
        layout = self.layout
        box = layout.box()
        col = box.column(align=True)
        col.label(text="Sub Panel label")
        
        obj =context.object
        if obj and obj.modifiers:
            sol_mods = [m for m in obj.modifiers if m.type =='SOLIDIFY']
        if not sol_mods:
            return
        for m in sol_mods:
            col.label(text=f"{m.name}")
            col.prop(m, "thickness")


classes = [VIEW3D_PT_test,
        ]

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


def unregister():
    for cls in classes:
        bpy.utils.unregister_class(cls)

if __name__ == "__main__":
    register()
$\endgroup$
5
  • $\begingroup$ This would also probably work perfectly for my purposes - in fact I'm going to save this example as a template for implementing modifier properties in my add-on UIs. $\endgroup$ May 7, 2022 at 9:57
  • 1
    $\begingroup$ Although the other method is fine, I think this one is more spot on and doesn't add any overhead. Using the modifier attributes directly also cuts on the code complexity. The depsgraph is updated when pretty much anything happens in Blender, so adding callbacks to this handler should be done with caution $\endgroup$
    – Gorgious
    May 7, 2022 at 10:24
  • $\begingroup$ May be this method has some limitations, because I noticed that if the N-panel is not selected to "Test Panel", the draw function does not run. $\endgroup$
    – X Y
    May 7, 2022 at 14:16
  • $\begingroup$ Not sure I understand the limitation as no non visible panels are drawn. the underlying property from the modifier is accessed in the same manner regardless. By not constantly forcing updates every couple milliseconds to every accessible property in a scene you improve performance. $\endgroup$
    – Ratt
    May 7, 2022 at 17:50
  • $\begingroup$ @XY also due to the fact there was no error checking in the original post to verify an object has modifiers and specifically a solidify modifier using the app handler will cause background warnings/errors to constantly occur when a camera or light or any object without the solidify modifier is selected. $\endgroup$
    – Ratt
    May 7, 2022 at 19:57

You must log in to answer this question.

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