I’m trying to write a python code which create and initialize n timers in a for loop and bind them to some events. The code bellow is an example of the way I’m doing it:
import wx
#dm1 = {a dewell times values dictionary}
#screens = [a list of dm1 keys]
trials = range(1, 3)
timers = range(0, 4)
class DM1(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)
panel = wx.Panel(self)
self.Go = wx.Button(panel, label = 'Go!', pos = (600, 450))
self.Bind(wx.EVT_BUTTON, self.BuildTimers, self.Go)
def BuildTimers(self, event):
self.timers = {}
cum_timer = 0
for trial in trials:
for timer in timers:
key = (timer, trial)
new_timer = wx.Timer(self)
cum_timer += dm1[screens[timer]]
new_timer.Start(cum_timer * 1000, False)
new_timer.mykey = key
self.timers[key] = new_timer
self.Bind(wx.EVT_TIMER, self.Screens)
def Screens(self, event):
if event.GetEventObject() == self.timers[event.GetEventObject().mykey]:
print event.GetEventObject().mykey
if event.GetEventObject().mykey[0] == 0:
print 'You bastard!'
if event.GetEventObject().mykey[0] == 1:
print 'you vicious...'
if event.GetEventObject().mykey[0] == 2:
print 'heartless bastard!'
if event.GetEventObject().mykey[0] == 3:
print 'Oh It makes me mad!'
app = wx.App()
frame = DM1(None, title = 'IG', size = (wx.DisplaySize()))
frame.Show()
app.MainLoop()
The timers don’t start at the time I specificate: the second loop of trial appear to overwrite the first. For example, the statement print event.GetEventObject().mykey, in the complete code, prints
(0, 1) (1, 1) (1, 2) (2, 1) (3, 1) (0, 2) (3, 1) (2, 1)
instead of
(0, 1) (1, 1) (2, 1) (3, 1) (0, 2) (1, 2) (2, 2) (3, 2)
I guess the problem is in the GetEventObject, but I don’t know a better way to bind the timers to the events. Does somebody have an idea?
Thanks a lot!
When using wxPython, I find it wiser to let widgets generate its own id using default parameters. Then you just ask the widget for its widget id. It is a dangerous practice, meaning really tricky to debug, to use manual magic number id values and sent the widget’s id values to that, especially for ids below 4000 as there are a bunch aready defined in the low range. Some internal methods will ask for “give me widget with id 1” for example and instead of getting some internal default widget, that method will get your timer widget instead.
Working with predefineds like TIMER_ID = 4000 or even more elusively buggy TIMER_ID = 4000 + someoffset, add additional maintainence costs to code.
I find the most flexable, reliable way is to user the id=-1 or id=wx.NewId(). Then say
or
or
where order is maintained and the index acts like how you’ve used the ID field in your code.
Another good practice is to avoid using “id” as a temp variable as there is the Python builtin function id() AND in wx, widgets have an id attribute too: