2
$\begingroup$

The callbacks still remain after I try to unregister using bpy.msgbus.clear_by_owner, leading to unwanted appending callbacks. Is there something wrong with this code? I do get the expected prints.

    CALLBACK_OBJECT_NAME = "callbackListener"

    if CALLBACK_OBJECT_NAME in bpy.context.scene:
        print("Clearing previous owner")
        bpy.msgbus.clear_by_owner(bpy.context.scene[CALLBACK_OBJECT_NAME])

    bpy.context.scene[CALLBACK_OBJECT_NAME] = {}

    subscribe_to = bpy.types.LayerObjects, "active"
    bpy.msgbus.subscribe_rna(
        key = subscribe_to,
        owner = bpy.context.scene[CALLBACK_OBJECT_NAME],
        args = (),
        notify = selectionChanged,
        )
$\endgroup$
  • $\begingroup$ Looking at blender source code, there's one more option to add in arguments for message bus subscription. Adding options = {'PERSISTENT'} prevents multiple additions. It still does not explain why above code does not work though. $\endgroup$ – KJS Mar 10 at 13:14
  • $\begingroup$ Does 'PERSISTENT' work for you? $\endgroup$ – lemon Mar 10 at 13:21
  • $\begingroup$ yes it works for me $\endgroup$ – KJS Mar 11 at 11:20
3
$\begingroup$

Owner can be any python object.+

Using example here https://developer.blender.org/P563 can use the simple python object class to instance a handle.

handle = object()

Can also use

handle = 4
handle = set()

Simple example throws callback when context object name is changed. Running in text editor (main thread) the handle is lost. A quick workaround is to save it to the driver namespace.

import bpy

handle = object()

# all branches below work
if 1:
    # To get some properties we need to prevent them being coerced into native Py types.
    subscribe_to = bpy.context.object.path_resolve("name", False)
elif 0:
    subscribe_to = bpy.context.object.location
else:
    # all object locations
    subscribe_to = bpy.types.Object, "location"

def notify_test(*args):
    print("Notify changed!", args)

bpy.msgbus.subscribe_rna(
    key=subscribe_to,
    owner=handle,
    args=(1, 2, 3),
    notify=notify_test,
)

# In general we won't need to explicitly publish, nevertheless - support it.
bpy.msgbus.publish_rna(key=subscribe_to)
bpy.app.driver_namespace["handle"] = handle
# ... to clear
# bpy.msgbus.clear_by_owner(handle)

To clear the callback via python console

>>> bpy.msgbus.clear_by_owner(
clear_by_owner(owner)
.. function:: clear_by_owner(owner)
Clear all subscribers using this owner.
>>> bpy.msgbus.clear_by_owner(bpy.app.driver_namespace['handle'])

If an immutable type like int is used (eg handle = 4 can clear from console with

bpy.msgbus.clear_by_owner(4)

but not for a dict handle = {}, possible the hassle in question code when setting the scene ID property.

In an addon can define the handle globally and remove in the unregister method, as it has the addon's module scope.

handle = object()

def register():
    # set up a callback with owner = handle

def unregister():
    bpy.msgbus.clear_by_owner(handle)
| improve this answer | |
$\endgroup$

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.