1
$\begingroup$

0 down vote favorite I can't find event change Position 3D Cursor when I left mouse click new position on the TOP screen.

When click change other position, system auto print new location(x,y,z).

Now i using bpy.context.scene.cursor_location : get the cursor location

I can't find event change, please help me

Thank you so much! enter image description here

$\endgroup$

1 Answer 1

2
$\begingroup$

You can use a handler to detect that.

Here I propose a little addon that demonstrates it:

enter image description here

The code contains:

  • A panel to start and stop the listening (the panel is in the scene properties)
  • Two operators: one to start and the second to stop
  • An utility class that handles various scene data changes

To use this utility class, you'll need to instantiate it giving the following parameters:

  • A context (for instance a scene)
  • A string corresponding to the data path to reach from the context (for instance 'cursor_location')
  • A function able to compare old/new values to check the changes
  • A function to call if there is a change
  • A flag indicating if the value is to be copied (in order to avoid 'pointers effect')

Here is the commented code:

import bpy
from mathutils import Vector

#A class that takes into account a context and one of its attributes value
#If the value changes a callback is fired
class EventWatcher:

    #Set of watchers
    eventWatchers = set()

    @staticmethod
    def AddWatcher( watcher ):
        EventWatcher.eventWatchers.add( watcher )    

    @staticmethod
    def RemoveWatcher( watcher ):
        EventWatcher.eventWatchers.remove( watcher )

    @staticmethod
    def RemoveAllWatchers():
        EventWatcher.eventWatchers.clear()

    #From 'context', 'path' needs to exist
    #'comparer' is to compare the previous value of context.path to its new value
    #'callback' is the cb called if the value if changed
    #'copyValue' indicates if the value needs to be copied (that can be needed as if not old and new value may point onto the same object)
    def __init__( self, context, path, comparer, callback, copyValue ):
        self.context = context
        self.path = path
        self.comparer = comparer
        self.callback = callback
        self.copyValue = copyValue
        self.currentValue = self.GetValue()

    def GetValue( self ):
        value = getattr( self.context, self.path )
        if self.copyValue:
            value = value.copy()
        return value

    def Fire( self ):
        newValue = self.GetValue()
        if self.comparer( self.currentValue, newValue ) == False:
            self.callback( self, newValue )
            self.currentValue = newValue

#Global loop on the watchers. This callback responds to scene_update_post global handler
def cb_scene_update(context):
    for ew in EventWatcher.eventWatchers:
        ew.Fire()

#To stop the calls at the scene_update_post event level
class StopCallback(bpy.types.Operator):
    bl_idname = "scene.stop_callback"
    bl_label = "Stop Callback"

    @classmethod
    def poll(cls, context):
        return cb_scene_update in bpy.app.handlers.scene_update_post

    def execute(self, context):
        bpy.app.handlers.scene_update_post.remove(cb_scene_update)
        return {'FINISHED'}

#To start the calls at the scene_update_post event level
class StartCallback(bpy.types.Operator):
    bl_idname = "scene.start_callback"
    bl_label = "Start Callback"

    @classmethod
    def poll(cls, context):
        return cb_scene_update not in bpy.app.handlers.scene_update_post

    def execute(self, context):
        bpy.app.handlers.scene_update_post.append(cb_scene_update)
        return {'FINISHED'}

#The panel is located in the scene properties
class SceneEventsPanel(bpy.types.Panel):
    bl_label = "Scene events"
    bl_idname = "OBJECT_PT_scene_events"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "scene"

    def draw(self, context):
        layout = self.layout
        row = layout.row()
        row.operator("scene.start_callback")
        row = layout.row()
        row.operator("scene.stop_callback")


def register():
    bpy.utils.register_class(SceneEventsPanel)
    bpy.utils.register_class(StartCallback)
    bpy.utils.register_class(StopCallback)

def unregister():
    bpy.utils.unregister_class(SceneEventsPanel)
    bpy.utils.unregister_class(StartCallback)
    bpy.utils.unregister_class(StopCallback)


if __name__ == '__main__':
    register()


print( '--------' )

#Example:

#The comparaison (for cursor location, it is a vector comparison)
def CompareLocation( l1, l2 ):
    return l1 == l2

#The callback to execute when the cursor's location changes    
def CompareLocationCallback( watcher, newValue ):
    print( 'New value', newValue )

#Install the watcher which will run the callback
EventWatcher.AddWatcher( EventWatcher( bpy.data.scenes[0], "cursor_location", CompareLocation, CompareLocationCallback, True ) )

$\endgroup$
14
  • $\begingroup$ This code can be included in the addon? $\endgroup$
    – hoald
    Commented Mar 28, 2017 at 3:51
  • $\begingroup$ @hoald, sure you can use it for whatever you want. Just do so that the Add/Remove watcher are handled properly so that you don't accumulate unwanted one. $\endgroup$
    – lemon
    Commented Mar 28, 2017 at 5:14
  • $\begingroup$ i tried create addon file, It error when i addon file: AttributeError: '_RestrictData' object has no attribute 'scenes' (LINE: EventWatcher.AddWatcher( EventWatcher( bpy.data.scenes[0], "cursor_location", CompareLocation, CompareLocationCallback, True ) )) $\endgroup$
    – hoald
    Commented Mar 28, 2017 at 8:08
  • $\begingroup$ May have to see your code, but, probably: don't keep the last part starting from "print( "------------" )" and the following (this part was for test purpose). $\endgroup$
    – lemon
    Commented Mar 28, 2017 at 8:17
  • $\begingroup$ I only add Top file: bl_info = { "name": "UPdate Scene", "author": "G6T", "version": (1, 0), "blender": (2, 78, 0), "location": "", "description": "Get new 3D Cursor", "warning": "", "wiki_url": "", "category": "Scene Update"} $\endgroup$
    – hoald
    Commented Mar 28, 2017 at 8:21

You must log in to answer this question.

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