1
$\begingroup$

I am trying to create add a keyframe option on Buttons in my Panel. As instructed by a tip here, using layout.use_property_split = True and layout.use_property_decorate = True seems to only add a keyframe option to sliders. Is it possible to enable keyframing for buttons?

import bpy
from bpy.props import BoolProperty

win_man = bpy.types.WindowManager
bool_prop = bpy.props.BoolProperty

def update_test(self, context):

    if not context.window_manager.test:
        test = 1 
    else:
        test = 0

    return

win_man.test = bool_prop(default = False, update = update_test)

class HelloWorldPanel(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "Hello World Panel"
    bl_idname = "OBJECT_PT_hello"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"

    def draw(self, context):

        wm = context.window_manager
        layout = self.layout
        layout.use_property_split = True
        layout.use_property_decorate = True
        obj = context.object

        col = layout.column()
        col.prop(obj, "location")
        row = self.layout.row()
        sub = row.row()
        label = "test = 1" if wm.test else "test = 0"
        sub.prop(wm, 'test', text=label, toggle=True)

def register():
    bpy.utils.register_class(HelloWorldPanel)

def unregister():
    bpy.utils.unregister_class(HelloWorldPanel)

if __name__ == "__main__":
    register()

Here is the test example used in the previous link with a button property added to demonstrate my point.


from bpy.props import BoolProperty

win_man = bpy.types.WindowManager
bool_prop = bpy.props.BoolProperty

scene_man = bpy.types.Scene

def update_test(self, context):

    if not bpy.context.scene.test:
        bpy.data.objects["Cube"].location[0] = 1

    else:
        bpy.data.objects["Cube"].location[0] = 0

    return

win_man.test = bool_prop(default = False, update = update_test)
scene_man.test = bool_prop(default = False, update = update_test)

class HelloWorldPanel(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "Hello World Panel"
    bl_idname = "OBJECT_PT_hello"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"

    def draw(self, context):
        loc = bpy.data.objects["Cube"].location[0]
        wm = context.window_manager
        sn = context.scene
        layout = self.layout
        layout.use_property_split = True
        layout.use_property_decorate = True
        obj = context.object

        row = self.layout.row()
        sub = row.row()
        label = "cube = 0" if sn.test else "cube = 1"

        sub.prop(sn, 'test', text=label, toggle=True)

        return
        icon = 'DECORATE_KEYFRAME' if sn.arm_ik else 'DECORATE'
        sub.operator("object.simple_operator", text="", emboss=False, icon=icon)

def register():
    bpy.utils.register_class(HelloWorldPanel)

def unregister():
    bpy.utils.unregister_class(HelloWorldPanel)

if __name__ == "__main__":
    register()

Here is what I tried. The keyframes now work but they don't save the position of the cube, they only seem to affect the button display. How do I make the keyframes react to the location of the cube instead?

$\endgroup$
  • $\begingroup$ @batFINGER, if the button was linked to a custom property would it still be impossible or could you somehow add a keyframe button that affects the custom property slider? $\endgroup$ – Jambo May 22 at 3:39
  • $\begingroup$ Scrub that, works fine, see answer. Just not on wm. $\endgroup$ – batFINGER May 22 at 4:19
  • $\begingroup$ If you have a new question ask a new question. $\endgroup$ – batFINGER May 23 at 19:17
  • $\begingroup$ Ok sorry, I'm rather new to this site. $\endgroup$ – Jambo May 23 at 19:23
1
$\begingroup$

Window manager properties are not animatable

Doh.. should have looked harder. The issue here is the use of window manager

>>> C.window_manager.keyframe_insert('test')
Traceback (most recent call last):
  File "<blender_console>", line 1, in <module>
TypeError: bpy_struct.keyframe_insert() property "test" not animatable

Use another ID type, Scene for example and all is sweet.

enter image description here

import bpy
from bpy.props import BoolProperty


def update_test(self, context):

    test = int(self.test)
    return


class HelloWorldPanel(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "Hello World Panel"
    bl_idname = "OBJECT_PT_hello"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"

    def draw(self, context):

        scene = context.scene
        layout = self.layout
        layout.use_property_split = True
        layout.use_property_decorate = True
        obj = context.object

        col = layout.column()
        col.prop(obj, "location")
        row = self.layout.row()
        sub = row.row()
        label = "test = 1" if scene.test else "test = 0"

        sub.prop(scene, 'test', text=label, toggle=True)

        return
        icon = 'DECORATE_KEYFRAME' if wm.test else 'DECORATE'
        sub.operator("object.simple_operator", text="", emboss=False, icon=icon)


def register():
    bpy.types.Scene.test = BoolProperty()
    bpy.utils.register_class(HelloWorldPanel)


def unregister():
    bpy.utils.unregister_class(HelloWorldPanel)


if __name__ == "__main__":
    register()

Notice can emulate this with an operator. Have put in the draw method to display only icon for operator (example toggles icon simply using bool value) Otherwise could pass the path to operator and keyframe insert, change icon based on key at that frame.

| improve this answer | |
$\endgroup$
  • $\begingroup$ I can't seem to implement this in my code because I don't understand how you run the update_test function when the button is pressed. I am trying to change a custom property for a bone so when the button is pressed, I need to run the function in a similar fashion to the if statement method above. Can you please clarify how you did this? Thanks. $\endgroup$ – Jambo May 23 at 15:35
  • $\begingroup$ Dont use the window manager. Simply wire the update method back into the property BoolProperty(update=update_test) if you want ti to run an update method. Because the property is on Scene, self is the scene. $\endgroup$ – batFINGER May 23 at 16:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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