1+ # Copyright 2009-2012 Ram Rachum.
2+ # This program is distributed under the MIT license.
3+
4+ # todo: daemonize?
5+ # todo: kickass idea: make all timers use one thread that will sleep smartly
6+ # to send all events correctly.
7+
8+ import threading
9+ import time
10+
11+ import wx
12+
13+ from python_toolbox .wx_tools .timing import cute_base_timer
14+
15+
16+ wxEVT_THREAD_TIMER = wx .NewEventType ()
17+ EVT_THREAD_TIMER = wx .PyEventBinder (wxEVT_THREAD_TIMER , 1 )
18+ '''Event saying that a `ThreadTimer` has fired.'''
19+
20+
21+ class ThreadTimer (cute_base_timer .CuteBaseTimer ):
22+ '''
23+ A timer for a wxPython app which runs on a different thread.
24+
25+ This solved a problem of wxPython timers being late when the program is
26+ busy.
27+ '''
28+
29+ n = 0
30+ '''The number of created thread timers.'''
31+
32+
33+ _EventHandlerGrokker__event_code = EVT_THREAD_TIMER
34+
35+
36+ def __init__ (self , parent ):
37+ '''
38+ Construct the ThreadTimer.
39+
40+ `parent` is the parent window.
41+ '''
42+
43+ cute_base_timer .CuteBaseTimer .__init__ (self , parent )
44+
45+ self .parent = parent
46+ '''The parent window.'''
47+
48+ ThreadTimer .n += 1
49+ self .wx_id = wx .NewId ()
50+ '''The ID of this timer, given by wxPython.'''
51+
52+ self .__init_thread ()
53+ self .alive = False
54+ '''Flag saying whether this timer is running.'''
55+
56+ def __init_thread (self ):
57+ '''Create the thread.'''
58+ thread_name = '' .join (('Thread used by ThreadTimer no. ' , str (self .n )))
59+ self .thread = Thread (self , name = thread_name )
60+ # Overwriting previous thread, so it'll get garbage-collected, hopefully
61+
62+ def start (self , interval ):
63+ '''Start the timer.'''
64+ if self .alive :
65+ self .stop ()
66+ self .interval = interval
67+ self .alive = True
68+ self .thread .start ()
69+
70+ def stop (self ):
71+ '''Stop the timer.'''
72+ self .alive = False
73+ self .thread .retired = True
74+ self .__init_thread ()
75+
76+ # Crutch for compatibilty with wx.Timer:
77+ Start = start
78+ Stop = stop
79+
80+ def GetId (self ):
81+ '''Get the wx ID of this timer.'''
82+ return self .wx_id
83+
84+
85+ class Thread (threading .Thread ):
86+ '''Thread used as a timer for wxPython programs.'''
87+ def __init__ (self , parent , name ):
88+ threading .Thread .__init__ (self , name = name )
89+ self .parent = parent
90+ self .retired = False
91+
92+ def run (self ):
93+ '''Run the thread. Internal function.'''
94+ interval_in_seconds = self .parent .interval / 1000.0
95+ def sleep ():
96+ time .sleep (interval_in_seconds )
97+
98+ sleep ()
99+ try :
100+ while self .parent .alive is True and self .retired is False :
101+ event = wx .PyEvent (self .parent .wx_id )
102+ event .SetEventType (wxEVT_THREAD_TIMER )
103+ wx .PostEvent (self .parent .parent , event )
104+ sleep ()
105+ except :
106+ return # Just so it wouldn't raise an error when wx is shutting down
0 commit comments