0
$\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$
0
$\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$
  • $\begingroup$ This code can be included in the addon? $\endgroup$ – hoald Mar 28 '17 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 Mar 28 '17 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 Mar 28 '17 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 Mar 28 '17 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 Mar 28 '17 at 8:21

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.