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$
4
  • $\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
    Commented May 22, 2020 at 3:39
  • $\begingroup$ Scrub that, works fine, see answer. Just not on wm. $\endgroup$
    – batFINGER
    Commented May 22, 2020 at 4:19
  • $\begingroup$ If you have a new question ask a new question. $\endgroup$
    – batFINGER
    Commented May 23, 2020 at 19:17
  • $\begingroup$ Ok sorry, I'm rather new to this site. $\endgroup$
    – Jambo
    Commented May 23, 2020 at 19:23

1 Answer 1

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.

$\endgroup$
2
  • $\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
    Commented May 23, 2020 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
    Commented May 23, 2020 at 16:15

You must log in to answer this question.

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