[python] Where are the mouse events in the API doc?

For Rhino.RhinoDoc there is a branch of all the events:

image

Where are the mouse events located?

image

How does it work with mouse events?
What I am trying to do is display a hint (tooltip) with the name of the viewport upon entering, then hiding (fade away) the hint after a while

With the MouseCallback class documentation opened on the right scroll down untill you see the methods. Look at the OnMouse* methods.

You are supposed to implement a custom class that overrides the ones you need. You may want to check specifically the OnMouseEnter, OnMouseHover and OnMouseLeave methods that all take a RhinoView.

Here a C++ sample - should be pretty much similar.

You’d do essentially the same:

  • inherit from MouseCallback
  • implement those event functions you want
  • get an instance of your own class (say in variable ivelynMouseTracker)
  • ivelynMouseTracker.Enabled=true; to enable
  • ivelynMouseTracker.Disabled=false; when done
1 Like

:thinking:

Why is it necessary to create my own class derived from this callback class and not similar to this?:

import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino
import time

tol = sc.doc.ModelAbsoluteTolerance

######################
### EVENT HANDLERS ###
######################
def object_added_event(sender, e):
    try:
        print "Object Added, Id =", e.ObjectId
    except Exception, ex:
        print ex

def object_selected_event(sender, e):
    try:
        for obj in e.RhinoObjects:
            obj_type = type(obj)
            #if 
            print "Selected Object Type =", obj_type
    except Exception, ex:
        print ex
def mouse_enter_viewport_event(sender,e):
    try:
        print "mouse entered ",e.view
    except Exception, ex:
        print ex

##############################
### EVENT HELPER FUNCTIONS ###
##############################

def obj_event_helper_func(event,sticky_key,event_name):
    #Event trigger helper function
    if sc.sticky.has_key(sticky_key):
        print "removing the callback "+event_name+"."
        stky = sc.sticky[sticky_key]
        #Rhino.RhinoDoc.AddRhinoObject -= stky
        exec("Rhino.RhinoDoc."+event_name+" -= stky")
        sc.sticky.Remove(sticky_key)
    else:
        print "adding the callback "+event_name+"."
        stky = event
        sc.sticky[sticky_key] = stky
        #Rhino.RhinoDoc.AddRhinoObject += stky
        exec("Rhino.RhinoDoc."+event_name+" += stky")




if __name__ == "__main__":
    ts = time.time()
    rs.EnableRedraw(False)
    
    obj_event_helper_func(object_added_event,"object_added_event","AddRhinoObject")
    obj_event_helper_func(object_selected_event,"object_selected_event","SelectObjects")
    
    
    
    print "Elapsed time is {:.2f}".format(time.time()-ts)

I do not understand

I can’t tell you why it is different, just that it is.

Here a quick sample in C#, just now created for you.

1 Like

“lovely” :smiley:

When you test the code you’ll see that the OnMouseHover gets called once after you enter a view and stop moving the mouse. There is a slight delay. You could use that as a timer when to hide your notification.

Thanks @nathanletwory, I appreciate the effort.

I’ll try to translate it to Python, because here I don’t have VS, and I am not allowed to install it.

I need to understand why these events are created differently. Any idea who can explain this to me?

Perhaps I can create a single class and put the methods (in the above code) in a similar manner?

I don’t know who invented CRhinoMouseCallback on which the RhinoCommon counterpart is built, but maybe @stevebaer or @dale know who the guilty part to that is.

As to understanding why it is different: does it really matter? It is not something that’ll change anytime soon. You know it is different, and how it is different.

These mouse events aren’t on the document because these aren’t document events. You aren’t changing anything in the document. At most these could be conceived to be on RhinoApp.

It matters, so I can understand it. I’m still not quite comfortable with my knowledge about events and any difference adds to the confusion. If both are events I’d like to implement similar ways of calling them.

For one I need to use sticky for the other not. One needs a class the other needs just a method. This is incomprehensible and I cannot use it until I understand it.

They are two ways of implementing an event system. They are different and at the level they are exposed can’t be implemented the same by client code (your code).

You could abstract the two in such a way that they look like they act the same, but that means creating some construct (probably a class with necessary bits and pieces) that internally use the two different event systems.

The events on the document are implemented using a listener pattern: you have functions (event handlers) that you register with the events.

The mouse callback uses a subclass system where you override functions you want to react on. An instance of such a MouseCallback-deriving subclass is your callback object, its overridden methods are like the event handlers in the former way.

1 Like

Thanks I’ll try to chew that one up a bit :slight_smile:

I found this thread:

This will be my starting point. Implementation of the helper function is similar using sticky. Just that you don’t subscribe to the event with the helper function but with the class I guess. I still need to process this in my head.

The use of sticky is there to ensure there is only one instance of a deriving class active. You can see that an instance is created in the else block (callback = SampleMouseCallback()), which is then stuck into sticky.

Note that running the test command multiple times now will toggle the state of that instance.

Further overrides you can make as per the C# sample. The e parameter you get into the overrides is the MouseCallbackEventArgs, so you can get to the view and its active viewport if there is any.

1 Like

is Event == Callback?

Conceptually yes.

I forgot to add that the sticky is most important in retaining instances and values between runs of commands during the same Rhino session.

1 Like

One more term I need to clarify to myself what does asynchronous callback mean?
Or more precisely, what asynchronous means in programming?

I wrote the RhinoCommon version and have tweaked the C++ version over the years. There are plenty of cases in the RhinoCommon SDK where you need to subclass an existing class and override functions to get callbacks as there are plenty of cases where events are used. This is pretty typical for a lot of libraries. I try to pick the right way to expose functionality based on the situation.

1 Like

Not synchronous or not serial. Just search for async and await on google and you’ll see many discussions of this topic for many different programming languages

Hi @stevebaer,

As far as I understand by creating a class derived from the MouseCallback class and “overriding” the eventhandlers inside (I’m sorry if eventhandler is not the correct term). I mean these OnMouseDown(self,e)

By instantiating the class you in fact subscribe to all the events that were overridden. Am I correct?

If yes, then is it possible that I create a class that subscribes to a bunch of Rhino.RhinoDoc events upon instantiation?

How do I do this?

Additional Question:
I noticed that OnMouseHover is triggered when changing viewports but not when hovering over 3d objects. Is this done by a different event?

Here’s my current code:

import System
import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino
import time

tol = sc.doc.ModelAbsoluteTolerance

######################
### EVENT HANDLERS ###
######################
class MouseCallbackClass(Rhino.UI.MouseCallback):
    """"""
    def OnMouseDown(self, e):
        print "OnMouseDown",e.Button
    
    """
    def OnEndMouseDown(self,e):
        print "OnEndMouseDown", e.Button
    """
    """"""
    def OnMouseUp(self,e):
        print "OnMouseUp",e.Button
    
    """
    def OnEndMouseUp(self,e):
        print "OnEndMouseUp",e.Button
    """
    """"""
    def OnMouseDoubleClick(self,e):
        print "OnMouseDoubleClick",e.Button
    
    """
    def OnMouseMove(self,e):
        print "OnMouseMove"
    """
    """
    def OnEndMouseMove(self,e):
        print "OnEndMouseMove"
    """
    """"""
    def OnMouseEnter(self,e):
        print "OnMouseEnter", e.View.MainViewport.Name
    
    """"""
    def OnMouseLeave(self,e):
        print "OnMouseLeave", e.View.MainViewport.Name
    
    """"""
    def OnMouseHover(self,e):
        print "OnMouseHover"
    


def object_added_event(sender, e):
    try:
        print "Object Added, Id =", e.ObjectId
    except Exception, ex:
        print ex

def object_selected_event(sender, e):
    try:
        for obj in e.RhinoObjects:
            obj_type = type(obj)
            #if 
            print "Selected Object Type =", obj_type
    except Exception, ex:
        print ex


##############################
### EVENT HELPER FUNCTIONS ###
##############################

def obj_event_helper_func(event,sticky_key,event_name):
    #Event trigger helper function
    if sc.sticky.has_key(sticky_key):
        print "removing the callback "+event_name+"."
        stky = sc.sticky[sticky_key]
        exec("Rhino.RhinoDoc."+event_name+" -= stky")
        sc.sticky.Remove(sticky_key)
    else:
        print "adding the callback "+event_name+"."
        stky = event
        sc.sticky[sticky_key] = stky
        exec("Rhino.RhinoDoc."+event_name+" += stky")

def mouse_event_helper_func():
    #Event trigger helper function
    if sc.sticky.has_key('TestSampleMouseCallback'):
        callback = sc.sticky['TestSampleMouseCallback']
        if callback:
            callback.Enabled = False
            callback = None
            sc.sticky.Remove('TestSampleMouseCallback')
    else:
        callback = MouseCallbackClass()
        callback.Enabled = True
        sc.sticky['TestSampleMouseCallback'] = callback
        #Rhino.RhinoApp.WriteLine("Click somewhere...")
        print "Listening for mouse events..."



if __name__ == "__main__":
    ts = time.time()
    rs.EnableRedraw(False)
    
    obj_event_helper_func(object_added_event,"object_added_event","AddRhinoObject")
    obj_event_helper_func(object_selected_event,"object_selected_event","SelectObjects")
    mouse_event_helper_func()
    
    
    print "Elapsed time is {:.2f}".format(time.time()-ts)

Actually I found this thread

I’ll try to do it myself