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?
How to store data between sessions for python plugin
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 scriptcontext.sticky.Remove("MyAddObjectEvent") else: 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.
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
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.
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.
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 else: 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
Implementing MLINE command in Rhino
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)?
Instead of storing the data on the object, you might consider storing the data in the document. Rhino has
SetDocumentUserText commands that allow for this.
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 scriptcontext.sticky.Remove(select_event_name) else: print "adding callback" func = eval(select_event_name) scriptcontext.sticky[select_event_name] = func Rhino.RhinoDoc.SelectObjects += func #Rhino.RhinoDoc.DeselectObjects += func DoSomething()
If i comment
SelectObjects, uncomment the two lines for
DeselectObjects, no event is fired. Anything i am doing wrong ?
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, 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
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.
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.