Monitor mouse event

Hi everyone:
I want to create a piece a python script to monitor mouse events, like object selection, object modified. And then call different function according to different event.
Is there any sample script to take reference?
Thanks in advance!

As scripting is not event driven, this might not be possible with Rhino.Python. You might consider writing a plug-in, using RhinoCommon, where this type of application is not difficult to put together.

What about using the COMMAND mode when create new script? Is that make the script run in plug-in way?

This actually can be done in python, though it may seem a bit unusual because it involve wiring up events that can be fired at any time and not necessarily in the scope of a single running script. There are many events in RhinoCommon that you can attach a callback function to. Here’s an example of having a function get called each time an object is added to the Rhino document.

import Rhino
import scriptcontext

def MyAddObjectEvent(sender, e):
    print "Object Added, Id =", e.ObjectId

#check to see if the callback is already assigned
if scriptcontext.sticky.has_key("MyAddObjectEvent"):
    print "removing the callback"
    func = scriptcontext.sticky["MyAddObjectEvent"]
    Rhino.RhinoDoc.AddRhinoObject -= func
    print "adding the callback"
    func = MyAddObjectEvent
    scriptcontext.sticky["MyAddObjectEvent"] = func
    Rhino.RhinoDoc.AddRhinoObject += func

If you run this script and then later add a line (or any geometry) to Rhino, the MyAddObject function will be called and will print out the Id of the object that was just added.

1 Like

Hi Steve, great idea using sticky for this. Do you know if it is possible to do the same from within a GHPython component? Best, Anders

sticky should also work in the context of GhPython

It does indeed, I use it all the time. Very useful functionality.

What I was rather poorly referring to was calling the Rhino.RhinoDoc.AddRhinoObject event from a GHPython component. I just tried it out quickly yesterday using your code and had no luck getting it working (works from the editPythonScript editor though). I have very little experience with events, but would like to get started. In this case I was looking to write a GHPython component which reads geometry from nested Rhino layers and have this component automatically update if new geometry is added to the Rhino doc.

I’m afraid I’m not currently on a Rhino machine, so I do not have any definitions to upload available.

I think I managed to get it working, see attached file. Still not entirely sure exactly what is going on or how to deal with “unassigning” the callback function if the GH definition is closed, the component is deleted etc. Anywho, one step closer :wink: (6.0 KB)

Hi @stevebaer,

apologize for warming this old thread up Steve. I’ve tried your example script above and found that the event is fired as well when an object is dragged or deleted. Is there anything i can do to make such events NOT fire on dragging ? I’m trying to attach a similar event to track if a specific object id is deleted using:

Rhino.RhinoDoc.DeleteRhinoObject += MyDeleteObjectEvent

for some unknown reason the event is fired if i just drag. In the MyDeleteObjectEvent function, i can compare e.ObjectId to detect which object fired the event. But how can i find out if the object (id) has been dragged or deleted if the event is fired in both cases ?


Our sdk can be a little tricky in the situations because to rhino a dragged object is really a comination of deleting an object and then adding one. This is how our undo mechanism works.

Hi Steve, i´ve feared about that. Unfortunately, if i try to check if the object has been deleted using IsDeleted, it returns True even when the object has just been dragged. Any other ways to check in the MyDeleteObjectEvent function if the object has really been deleted ?

I´ve tried to compare area centroids as well to distinguish between drag OR delete. But that didn`t work either.


Hi Clement,

When you drag an object, a RhinoDoc.ReplaceRhinoObject event will be triggered, following by RhinoDoc.DeleteRhinoObject and RhinoDoc.AddRhinoObject events.

If you want to check out all of the events in action, download and build the following sample.

– Dale

Hi Dale,

thanks, that`s what i do now, first check if the replace event has been called before the delete event, and if not, the object has been deleted.

replace = False 

def MyDeleteObjectEvent(sender, e):
    global replace
    if e.ObjectId == id:
        if replace == True: replace = False
            print "Object Deleted"
            replace = False
            #  remove both events here

def MyReplaceObjectEvent(sender, e):
    global replace
    if e.ObjectId == id: replace = True

…its probably not the cleanest way :wink:



@stevebaer @dale
Sorry for warming up this thread again. I’ve created a binding using UserString. Basically, I store the GUID of a TextDot to an Object. When the object is moved/scaled/copied, the textdot will follow the object and update its text. Everything else has been working greatly, except that when I delete the original object, I cannot delete the TextDot. Because when the original object is deleted, the .GetUserString() method won’t work, since the object doesn’t exist anymore. Is there a way I can bypass this? Can I store the binding information somewhere else in the document (need to be persistent)?

Thank you!

Instead of storing the data on the object, you might consider storing the data in the document. Rhino has GetDocumentUserText and SetDocumentUserText commands that allow for this.

Hi @stevebaer,

i am trying to subscribe to Rhino.RhinoDoc.DeselectObjects event similar as shown in your example above but it is not working. Below one is a code snippet, subscribing to SelectObjects seems to work:

import Rhino
import scriptcontext

def MySelectObjectEvent(sender, e):
    print "Object(s) selected =", e.Selected
def DoSomething():
    select_event_name = "MySelectObjectEvent"
    if scriptcontext.sticky.has_key(select_event_name):
        print "removing callback"
        func = scriptcontext.sticky[select_event_name]
        Rhino.RhinoDoc.SelectObjects -= func
        #Rhino.RhinoDoc.DeselectObjects -= func
        print "adding callback"
        func = eval(select_event_name)
        scriptcontext.sticky[select_event_name] = func
        Rhino.RhinoDoc.SelectObjects += func
        #Rhino.RhinoDoc.DeselectObjects += func


If i comment SelectObjects, uncomment the two lines for DeselectObjects, no event is fired. Anything i am doing wrong ?


Hi Clement,

There are 2 “deselect” events you can watch:


If you have a bunch of selected objects and you hold the key and click on one of the selected objects, a RhinoDoc.DeselectObjects event will be triggered.

If you click in the viewport and not on any object, the RhinoDoc.DeselectAllObjects event will be triggered.

Does this help?

– Dale

@dale, thanks that helped and makes sense now after i’ve tried it.

It took me a while to figure out that if there is an error in one of the event functions, it does not print anything. (it also does not complain about the error).

Is there a way to keep track of the objects which where deselected in RhinoDoc.DeselectAllObjects ?


Hi Clement,

Unless you were already tracking selected objects, by way of RhinoDoc.SelectObjects, then probably not.

Of course, there is the SelPrev command.

There is also a newer OnChangeObjectSelectState event in core Rhino that is called when an object’s selected state changes. But this isn’t available in RhinoCommon.

– Dale

Thanks Dale,

i’ll try to create my own selection state list and update it using the available methods. Something like OnChangeObjectSelectState would have been be quite useful.