StopWatch issue

Hi,

Why is this code immediately stopped when run inside Rhino.

import System

from System.Diagnostics import Stopwatch


def Main():
    zSW = Stopwatch.StartNew()
    
    
    print "StopWatch is running."
    print "(Press Enter to stop the StopWatch.)"
    while System.Console.Read() != 'q':#True:
        zSW.Stop()
        print "Elapsed time: ",zSW.Elapsed.ToString()
        return 0
        
        
def OnTimedEvent(sender,e):
    #print "Yello!"
    print e.SignalTime
    print "{0}".format(System.DateTime.Now.Millisecond)

    
if __name__=="__main__":
    Main()

probably because you aren’t running a console based application

1 Like

Thanks @stevebaer,

Is there a way I can modify this to work with Rhino terminal?

I assume my issue is in this line:
while System.Console.Read() != 'q':

1 Like

What does the exclamation mark mean here:
m_enabled = !m_enabled;

you’re comparing an object with itself? :thinking:

not comparing I guess, but assigning the inverted value. hmm
How would that look in Python?

if m_enabled == 1:
    m_enabled = 0
else:
    m_enabled = 1

?

That is not a comparison, it is an assignment. The ! means not.

m_enabled is a boolean, so in Python it would look like:

m_enabled = not m_enabled
1 Like

Thanks, I didn’t know I can use not this way.

while not ivelin.knows():
  ivelin.listen(nathan.tells_secret()) # important lessons
  ivelin.digest_information(duration=1.0) # side effect: may change outcome of 'knows()'
3 Likes

I’d love to see how the two classes look like.
It will be very educational.

I crashed rhino only three times last night. I managed to make both key event to work as well as the timer, but not able to stop the timer using the key.

Btw, the exanple above is triggered twice, upon keyDown and keyUp. How can I do it once?

You’ll have to keep track of state yourself, then react on the state change you need.

Can you post your current, minimal code?

This is the code, that makes both concepts work, but not properly.

import System
from System.Timers import Timer, ElapsedEventHandler

import Rhino
import scriptcontext as sc
import rhinoscriptsyntax as rs

#sw_enabled = False

def Main(sw_enabled = None):
    if sw_enabled == None: return
    
    if sw_enabled == True:
        aTimer = Timer()
        aTimer.Interval = 1000#1
        aTimer.Enabled = True
        aTimer.Elapsed += ElapsedEventHandler(OnTimedEvent)
        
    elif sw_enabled == False:
        aTimer = Timer()
        aTimer.Interval = 1000#1
        aTimer.Enabled = False
        aTimer.Elapsed -= ElapsedEventHandler(OnTimedEvent)
        
    else:
        return


def OnTimedEvent(sender,e):
    #print "Yello!"
    print e.SignalTime
    #print "{0}".format(System.DateTime.Now.Seconds)



def object_added_event(key):
    if key == 0x2E:
        print "Yello!"
        Main(False)


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.RhinoApp.KeyboardHookEvent -= stky
        exec("Rhino.RhinoApp."+event_name+" -= stky")
        sc.sticky.Remove(sticky_key)
        Main(False)
    else:
        print "adding the callback "+event_name+"."
        stky = event
        sc.sticky[sticky_key] = stky
        #Rhino.RhinoApp.KeyboardHookEvent += stky
        exec("Rhino.RhinoApp."+event_name+" += stky")
        Main(True)





if __name__=="__main__":
    
    obj_event_helper_func(object_added_event,"object_added_event","KeyboardEvent")
    


I have to restart Rhino to stop the timer in this example :frowning:

You are also creating a new timer object in the sw_enabled==False block. This means you’re never stopping the original one…

Here a possible script:

import System
from System.Timers import Timer, ElapsedEventHandler

import Rhino
import scriptcontext as sc
import rhinoscriptsyntax as rs

aTimer = None

def Main(sw_enabled = None):
    global aTimer
    if sw_enabled == None: return
    
    if sw_enabled and aTimer is None:
        print "start timer"
        aTimer = Timer()
        aTimer.Interval = 1000#1
        aTimer.Enabled = True
        aTimer.Elapsed += ElapsedEventHandler(OnTimedEvent)
    else:
        if not (aTimer is None):
            print "stop timer"
            aTimer.Interval = 1000#1
            aTimer.Enabled = False
            aTimer.Elapsed -= ElapsedEventHandler(OnTimedEvent)
            aTimer = None

def OnTimedEvent(sender,e):
    print e.SignalTime

class KeyboardEventHandler():
    def __init__(self):
        print "add evt handler"
        Rhino.RhinoApp.KeyboardEvent += self.object_added_event
        self.del_down = False

    def disable(self):
        print "remove evt handler"
        Rhino.RhinoApp.KeyboardEvent -= self.object_added_event

    
    def object_added_event(self, key):
        if key == 0x2E: # DELETE
            self.del_down = not self.del_down
            if self.del_down:
                print "key DOWN event for DELETE... :O !"
                Main(False)


def obj_event_helper_func(sticky_key,event_name):
        stky = sc.sticky.pop(sticky_key, None)
        if stky:
            stky.disable()
            stky = None
            Main(False)
        else:
            print "adding the callback "+event_name+"."
            stky = KeyboardEventHandler()
            sc.sticky[sticky_key] = stky
            Main(True)

if __name__=="__main__":
    obj_event_helper_func("object_added_event","KeyboardEvent")
2 Likes

Thanks @nathanletwory,

I knew I had to use a global variable, just wasn’t sure how exactly and if I should use sticky for that.

Interesting to see that it wasn’t necessary to get both the timer and the key event in the same class.

The key down event also in your example seem to execute both on down and up.
I guess that’s just how it is.

Global variable is actually not that smart here. It is much better to encapsulate in a class, pretty much like the event handler class, and stick it in the sticky dictionary. Most important lesson here is that you were creating a new Timer each time you called your Main.

But it prints only once, right? the self.sel_down is the variable holding the state. I mentioned in an earlier reply that you have to keep track of key state yourself, this is it. Assume that on first running of the script nothing is pressed. Then for each key each event toggles state.

It isn’t necessary, you can do two classes. I was just lazy and wanted primarily to show that you shouldn’t create a new Timer every time (pun intended).

I did want to clean out the icky use of exec. Don’t do that ever - unless you’re writing a parser and want to run live code changes… But still, don’t do that ever.

1 Like

it prints twice if you press slowly. Can I manipulate the “hold” time somehow?

I have to admit, I didn’t know I can store class instance in the sticky :upside_down_face:
But also my implementation allows me to use the same helper function for any key event. Or any event for that matter by simply changing the string in exec(). I’m a script kiddie, copy/paste working code is essential. Even if it is done by me :stuck_out_tongue_winking_eye: . When I create code about something today, and I have to do the same code in half a year from now. It will most certainly be different. Maybe that’s normal but I prefer to copy existing code and adjust to the desired functionality.

Why, what is the issue with it? I like live code. I actually think if Rhino was made to allow subprocesses of the python engine to run without locking Rhino. It all would run much faster and more reliably.

I guess that is the key repeat. Not sure how to work around that.

For event handlers I look in our dev samples repository:

If you make a mistake there will be a crash instead of the script just failing to start.

No idea about that. I don’t know how the internals work for IronPython, but doing so with CPython requires great care with the GIL, and access to data in the document (from my Blender coding experience).

If implemented, and used, correctly.

1 Like