From 5de01f8ab61f3f7c0d1046c70802df82ee8b3028 Mon Sep 17 00:00:00 2001 From: Robin Dunn Date: Sun, 25 Sep 2011 04:21:11 +0000 Subject: [PATCH] Add wx.Timer and wx.CallLater git-svn-id: https://svn.wxwidgets.org/svn/wx/wxPython/Phoenix/trunk@69193 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- etg/_core.py | 1 + etg/timer.py | 65 +++++++++++++++ src/core_ex.py | 171 ++++++++++++++++++++-------------------- unittests/test_timer.py | 93 ++++++++++++++++++++++ 4 files changed, 244 insertions(+), 86 deletions(-) create mode 100644 etg/timer.py create mode 100644 unittests/test_timer.py diff --git a/etg/_core.py b/etg/_core.py index 32ea3bc2..d0bdf5ca 100644 --- a/etg/_core.py +++ b/etg/_core.py @@ -82,6 +82,7 @@ INCLUDES = [ 'defs', 'apptrait', 'app', + 'timer', 'window', 'validate', 'panel', diff --git a/etg/timer.py b/etg/timer.py new file mode 100644 index 00000000..ede16b03 --- /dev/null +++ b/etg/timer.py @@ -0,0 +1,65 @@ +#--------------------------------------------------------------------------- +# Name: etg/timer.py +# Author: Robin Dunn +# +# Created: 21-Sept-2011 +# Copyright: (c) 2011 by Total Control Software +# License: wxWindows License +#--------------------------------------------------------------------------- + +import etgtools +import etgtools.tweaker_tools as tools + +PACKAGE = "wx" +MODULE = "_core" +NAME = "timer" # Base name of the file to generate to for this script +DOCSTRING = "" + +# The classes and/or the basename of the Doxygen XML files to be processed by +# this script. +ITEMS = [ 'wxTimer', + 'wxTimerRunner', + 'wxTimerEvent', + ] + +#--------------------------------------------------------------------------- + +def run(): + # Parse the XML file(s) building a collection of Extractor objects + module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING) + etgtools.parseDoxyXML(module, ITEMS) + + #----------------------------------------------------------------- + # Tweak the parsed meta objects in the module object as needed for + # customizing the generated code and docstrings. + + c = module.find('wxTimer') + assert isinstance(c, etgtools.ClassDef) + + c = module.find('wxTimerRunner') + c.addPrivateCopyCtor() + + module.addPyCode('EVT_TIMER = wx.PyEventBinder( wxEVT_TIMER )') + + module.addPyCode("""\ + class PyTimer(Timer): + '''This timer class is passed the callable object to be called when the timer expires.''' + def __init__(self, notify): + Timer.__init__(self) + self.notify = notify + + def Notify(self): + if self.notify: + self.notify() + """) + + #----------------------------------------------------------------- + tools.doCommonTweaks(module) + tools.addGetterSetterProps(module) + tools.runGenerators(module) + + +#--------------------------------------------------------------------------- +if __name__ == '__main__': + run() + diff --git a/src/core_ex.py b/src/core_ex.py index 2a6f5327..c0f4e275 100644 --- a/src/core_ex.py +++ b/src/core_ex.py @@ -49,14 +49,13 @@ def deprecated(item, msg=''): """ import warnings if isinstance(item, type): - # It's a class. Make a subclass that raises a warning. + # It is a class. Make a subclass that raises a warning. class DeprecatedClassProxy(item): def __init__(*args, **kw): warnings.warn("Using deprecated class. %s" % msg, wxPyDeprecationWarning, stacklevel=2) item.__init__(*args, **kw) DeprecatedClassProxy.__name__ = item.__name__ - DeprecatedClassProxy.__doc__ = item.__doc__ return DeprecatedClassProxy elif callable(item): @@ -191,103 +190,103 @@ def CallAfter(callableObj, *args, **kw): #---------------------------------------------------------------------------- -## class CallLater: -## """ -## A convenience class for `wx.Timer`, that calls the given callable -## object once after the given amount of milliseconds, passing any -## positional or keyword args. The return value of the callable is -## availbale after it has been run with the `GetResult` method. +class CallLater(object): + """ + A convenience class for `wx.Timer`, that calls the given callable + object once after the given amount of milliseconds, passing any + positional or keyword args. The return value of the callable is + availbale after it has been run with the `GetResult` method. + + If you don't need to get the return value or restart the timer + then there is no need to hold a reference to this object. It will + hold a reference to itself while the timer is running (the timer + has a reference to self.Notify) but the cycle will be broken when + the timer completes, automatically cleaning up the wx.CallLater + object. + + :see: `wx.CallAfter` + """ + def __init__(self, millis, callableObj, *args, **kwargs): + assert callable(callableObj), "callableObj is not callable" + self.millis = millis + self.callable = callableObj + self.SetArgs(*args, **kwargs) + self.runCount = 0 + self.running = False + self.hasRun = False + self.result = None + self.timer = None + self.Start() -## If you don't need to get the return value or restart the timer -## then there is no need to hold a reference to this object. It will -## hold a reference to itself while the timer is running (the timer -## has a reference to self.Notify) but the cycle will be broken when -## the timer completes, automatically cleaning up the wx.CallLater -## object. - -## :see: `wx.CallAfter` -## """ -## def __init__(self, millis, callableObj, *args, **kwargs): -## assert callable(callableObj), "callableObj is not callable" -## self.millis = millis -## self.callable = callableObj -## self.SetArgs(*args, **kwargs) -## self.runCount = 0 -## self.running = False -## self.hasRun = False -## self.result = None -## self.timer = None -## self.Start() - -## def __del__(self): -## self.Stop() + def __del__(self): + self.Stop() -## def Start(self, millis=None, *args, **kwargs): -## """ -## (Re)start the timer -## """ -## self.hasRun = False -## if millis is not None: -## self.millis = millis -## if args or kwargs: -## self.SetArgs(*args, **kwargs) -## self.Stop() -## self.timer = wx.PyTimer(self.Notify) -## self.timer.Start(self.millis, wx.TIMER_ONE_SHOT) -## self.running = True -## Restart = Start + def Start(self, millis=None, *args, **kwargs): + """ + (Re)start the timer + """ + self.hasRun = False + if millis is not None: + self.millis = millis + if args or kwargs: + self.SetArgs(*args, **kwargs) + self.Stop() + self.timer = wx.PyTimer(self.Notify) + self.timer.Start(self.millis, wx.TIMER_ONE_SHOT) + self.running = True + Restart = Start -## def Stop(self): -## """ -## Stop and destroy the timer. -## """ -## if self.timer is not None: -## self.timer.Stop() -## self.timer = None + def Stop(self): + """ + Stop and destroy the timer. + """ + if self.timer is not None: + self.timer.Stop() + self.timer = None -## def GetInterval(self): -## if self.timer is not None: -## return self.timer.GetInterval() -## else: -## return 0 + def GetInterval(self): + if self.timer is not None: + return self.timer.GetInterval() + else: + return 0 -## def IsRunning(self): -## return self.timer is not None and self.timer.IsRunning() + def IsRunning(self): + return self.timer is not None and self.timer.IsRunning() -## def SetArgs(self, *args, **kwargs): -## """ -## (Re)set the args passed to the callable object. This is -## useful in conjunction with Restart if you want to schedule a -## new call to the same callable object but with different -## parameters. -## """ -## self.args = args -## self.kwargs = kwargs + def SetArgs(self, *args, **kwargs): + """ + (Re)set the args passed to the callable object. This is + useful in conjunction with Restart if you want to schedule a + new call to the same callable object but with different + parameters. + """ + self.args = args + self.kwargs = kwargs -## def HasRun(self): -## return self.hasRun + def HasRun(self): + return self.hasRun -## def GetResult(self): -## return self.result + def GetResult(self): + return self.result -## def Notify(self): -## """ -## The timer has expired so call the callable. -## """ -## if self.callable and getattr(self.callable, 'im_self', True): -## self.runCount += 1 -## self.running = False -## self.result = self.callable(*self.args, **self.kwargs) -## self.hasRun = True -## if not self.running: -## # if it wasn't restarted, then cleanup -## wx.CallAfter(self.Stop) + def Notify(self): + """ + The timer has expired so call the callable. + """ + if self.callable and getattr(self.callable, 'im_self', True): + self.runCount += 1 + self.running = False + self.result = self.callable(*self.args, **self.kwargs) + self.hasRun = True + if not self.running: + # if it wasn't restarted, then cleanup + wx.CallAfter(self.Stop) -## Interval = property(GetInterval) -## Result = property(GetResult) + Interval = property(GetInterval) + Result = property(GetResult) diff --git a/unittests/test_timer.py b/unittests/test_timer.py new file mode 100644 index 00000000..b8cf2fa3 --- /dev/null +++ b/unittests/test_timer.py @@ -0,0 +1,93 @@ +import imp_unittest, unittest +import wtc +import wx + +#--------------------------------------------------------------------------- + +class timer_Tests(wtc.WidgetTestCase): + + def waitFor(self, milliseconds): + intervals = milliseconds/100 + while intervals > 0: + wx.MilliSleep(100) + self.myYield() + if hasattr(self, 'flag') and self.flag: + break + intervals -= 1 + + + def onTimerEvt(self, *evt): + self.flag = True + + + def test_timerOwner1(self): + t = wx.Timer(self.frame) + self.flag = False + self.frame.Bind(wx.EVT_TIMER, self.onTimerEvt, t) + t.Start(250, wx.TIMER_ONE_SHOT) + self.waitFor(500) + self.assertTrue(self.flag) + + + def test_timerOwner2(self): + t = wx.Timer(self.frame) + self.flag = False + self.frame.Bind(wx.EVT_TIMER, self.onTimerEvt, t) + t.Start(1000, wx.TIMER_ONE_SHOT) + # timer will not have expired yet by this time, so flag shouldn't be set + self.waitFor(500) + self.assertFalse(self.flag) + + + def test_timerPyTimer(self): + t = wx.PyTimer(self.onTimerEvt) + self.flag = False + t.Start(250, wx.TIMER_ONE_SHOT) + self.waitFor(500) + self.assertTrue(self.flag) + + + def test_timerDerivedClass(self): + class MyTimer(wx.Timer): + def __init__(self): + wx.Timer.__init__(self) + self.flag = False + def Notify(self): + self.flag = True + + t = MyTimer() + t.Start(250, wx.TIMER_ONE_SHOT) + self.waitFor(500) + self.assertTrue(t.flag) + + + def onCallLater(self): + self.flag = True + return 1234 + + def test_timerCallLater1(self): + # simple CallLater usage + wx.CallLater(250, self.onCallLater) + self.waitFor(500) + self.assertTrue(self.flag) + + + def test_timerCallLater2(self): + # test getting the result and restarting the CallLater + cl = wx.CallLater(250, self.onCallLater) + self.assertTrue(cl.IsRunning()) + self.waitFor(500) + self.assertTrue(self.flag) + self.assertTrue(cl.GetResult() == 1234) + self.flag = False + cl.Restart() + self.waitFor(500) + self.assertTrue(self.flag) + + + +#--------------------------------------------------------------------------- + + +if __name__ == '__main__': + unittest.main()