3
$\begingroup$

If I move an object or rotate an object and press Enter to confirm, I would like to trigger a function. Is this possible?

I did research on app handlers and msgbus to no avail. Is msgbus deprecated in Blender 3.4? Because the documentation's sample code is not working for me.

I would like this. For example, pseudocode I'm trying to make:

def on_transform_complete(event):
    print("transform complete/confirmed")

my_object.addEventListener("TRANSFORM_COMPLETE", on_transform_complete)

Here's a similar post using scene_update_post, but it's outdated now and does not work anymore.

I did experiment on bpy.app.handlers.depsgraph_update_post, but the problem is that it keeps updating while dragging object, but I need my update to trigger only exactly once after the drag is confirmed with a final position or rotation or scale. There must be some "complete" event that gets dispatched which I can listen or subscribe to.

$\endgroup$
2

2 Answers 2

3
$\begingroup$

enter image description here

I noticed bpy.context.active_operator returns a pointer to a different location on the last callback to depsgraph_update_post when moving an object with the mouse. It means the test for equality between the two will likely yield False. I don't know how or why but we can leverage that "feature".

enter image description here

I'll piggyback on james_t's answer on this same Q&A.

import bpy
    
def transformEvent(obj, scene):
    print('transformEvent')

def on_depsgraph_update(scene):
    depsgraph = bpy.context.evaluated_depsgraph_get()
    if on_depsgraph_update.operator is None:
        on_depsgraph_update.operator = bpy.context.active_operator
    for update in depsgraph.updates:
        if not update.is_updated_transform:
            continue
        if on_depsgraph_update.operator == bpy.context.active_operator:
            continue
        obj = bpy.context.active_object
        transformEvent(obj, scene)
        on_depsgraph_update.operator = None

on_depsgraph_update.operator = None

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

$\endgroup$
6
  • 1
    $\begingroup$ Hey! i took a look at the pointer as well and didn't notice they were different! i should've paid closer attention haha awesome! $\endgroup$ Jan 9, 2023 at 7:55
  • 1
    $\begingroup$ wow this hack is the correct solution since there is no other solution thank you sooo much! XD $\endgroup$ Jan 9, 2023 at 7:58
  • 2
    $\begingroup$ @HarryMcKenzie hehe glad it helped :) $\endgroup$
    – Gorgious
    Jan 9, 2023 at 9:02
  • $\begingroup$ Something like this should be added to the scripting Templates. I suggest this in rightclickselect blender.community/c/rightclickselect/KQ6G -- perhaps vote or comment on this? $\endgroup$
    – james_t
    Jan 9, 2023 at 17:00
  • $\begingroup$ @james_t agreed ! although it's a bit hacky so I think the devs will say they prefer waiting for an officially designed and supported feature, which may or may not come in our lifetime >< $\endgroup$
    – Gorgious
    Jan 9, 2023 at 17:23
4
$\begingroup$

Here is a script that will trigger when I move an object in the 3d View

import bpy
    
def transformEvent(obj, scene):
    print('transformEvent')

def on_depsgraph_update(scene):
    depsgraph = bpy.context.evaluated_depsgraph_get()
    for update in depsgraph.updates:
        if update.is_updated_transform:
            obj= bpy.context.active_object
            transformEvent(obj, scene)

# Make blender call on_depsgraph_update after each
# update of Blender's internal dependency graph
bpy.app.handlers.depsgraph_update_post.append(on_depsgraph_update)
$\endgroup$
7
  • $\begingroup$ Hey cool thanks for the new answer. I'll have to check it tomorrow. Does it only trigger once? $\endgroup$ Jan 8, 2023 at 18:51
  • 1
    $\begingroup$ @HarryMcKenzie -- no it still suffers from being "invoked too often". Might have to set a timer event to then do whatever... ugh! perhaps there's some way to see if LMB is up. $\endgroup$
    – james_t
    Jan 8, 2023 at 18:51
  • $\begingroup$ oh no :( but it looks like the solution is very close! $\endgroup$ Jan 8, 2023 at 18:53
  • $\begingroup$ you can get the current operator with bpy.context.active_operator. It's possible the last callback happens when the operator is finished so it will return None otherwise it will point to the transform operator. wild guess :) $\endgroup$
    – Gorgious
    Jan 8, 2023 at 21:41
  • 2
    $\begingroup$ I think I found something. Looks hacky though. I'll post an answer $\endgroup$
    – Gorgious
    Jan 9, 2023 at 7:39

You must log in to answer this question.

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