Say I want yo have a float property in the 3DView Toolbar (T), and make it update in realtime several properties in the selected object without using drivers. For example, the "scale" of an object, its an array of 3 values, but I don't want the UI to display its three values, because I want to use only one float slider to drive the three at once (with the intention to preserve the proportion). Even more, think that this could be very useful if I want to drive any kind of values together with just a single slider, not only the scale's array. I spent several days investigating and trying to achieve that, but I finally understood that Panels and Operators are instances of well defined classes which draw functions remain separated, and I can't just make a call from a Panel to a property defined inside an Operator (I use the operator because I want it to update the object in realtime).

Here's a very simple example, just to illustrate the point (I didn't include an Operator here). Note that the script only changes the object's size when the script is rerun.

import bpy

bpy.types.WindowManager.float = bpy.props.FloatProperty(name="Object's Scale", default=1.0)

class OBPanel(bpy.types.Panel):
    bl_label = "Selected Object"
    bl_idname = "selected_object"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'
    bl_category = "Tools"
    bl_context = "objectmode"

    def draw(self, context):
        wm = context.window_manager
        layout = self.layout
        layout.row().prop(wm, 'float')

    wm = bpy.context.window_manager
    bpy.context.object.scale = wm.float, wm.float, wm.float


def register():
    bpy.utils.register_module(__name__)

def unregister():
    bpy.utils.unregister_module(__name__)

if __name__ == "__main__":
    register()
  • 2
    scale = wm.float, wm.float, wm.float should be inside the update function – Chebhou May 13 '16 at 10:03
  • Finally! I get realtime updates! I love this technique. Thank you. – Chaos May 13 '16 at 10:06
  • 1
    Best to add your own answer, that shows the working example, to help others. – ideasman42 May 13 '16 at 10:11
up vote 3 down vote accepted

Yes, this is possible, it can be done 2 ways.

  • Using a property set or update callback.
    This lets you either use your property as a way to access other data (by having get & set callbacks, you could for example, keep your property outside of the blend file even).
    With an update function you can use this property to control others.
    See https://www.blender.org/api/blender_python_api_current/bpy.props.html#get-set-example
  • Using drivers, although these need to be setup in the file each time and probably not what you're after.

FINAL UPDATE:

I added the update function and this code works as I wanted. Cheers!

import bpy

def update_func(self, context):
    wm = context.window_manager
    context.object.scale = wm.float, wm.float, wm.float

bpy.types.WindowManager.float = bpy.props.FloatProperty(
        update=update_func,
        name="Object's Scale",
        default=1.0,
        )

class OBPanel(bpy.types.Panel):
    bl_label = "Selected Object"
    bl_idname = "selected_object"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'
    bl_category = "Tools"
    bl_context = "objectmode"

    def draw(self, context):
        wm = context.window_manager
        layout = self.layout
        layout.row().prop(wm, 'float')

def register():
    bpy.utils.register_module(__name__)

def unregister():
    bpy.utils.unregister_module(__name__)

if __name__ == "__main__":
    register()
  • Note, using active object in an update function isn't great practice. Ideally you'd add a property on the object which modified other object properties. – ideasman42 May 13 '16 at 10:24

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.

Not the answer you're looking for? Browse other questions tagged or ask your own question.