我正在尝试编写一个python代码,该代码在for循环中创建并初始化 n 计时器,并将它们绑定到某些事件。下面的代码是我正在做的方式的一个例子:
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()
定时器在我指定的时间没有开始:trial
的第二个循环似乎覆盖了第一个循环。例如,完整代码中的语句print event.GetEventObject().mykey
打印
(0,1)(1,1)(1,2)(2,1)(3,1)(0,2)(3,1)(2,1)
而不是
(0,1)(1,1)(2,1)(3,1)(0,2)(1,2)(2,2)(3,2)
我想问题出在GetEventObject
,但我不知道将计时器绑定到事件的更好方法。有人有想法吗?
非常感谢!
答案 0 :(得分:1)
使用wxPython时,我发现让widgets使用默认参数生成自己的id更明智。然后,您只需询问小部件的小部件ID。这是一个危险的做法,意味着调试非常棘手,使用手动魔术数字id值并将小部件的id值发送到该值,特别是对于4000以下的ID,因为在低范围内定义了一堆。例如,一些内部方法将要求“给我一个id为id的小部件”,而不是获取一些内部默认小部件,该方法将取代你的计时器小部件。
使用预定义内容(如TIMER_ID = 4000或甚至更难以捉摸的错误TIMER_ID = 4000 + someoffset),为代码添加额外的维护成本。
我发现最灵活,最可靠的方法是使用id = -1或id = wx.NewId()。然后说
ident = myTimer.GetId()
self.timers[ ident ] = myTimer
或
self.timers[ myTimer ] = myTimer
或
self.timers.append( myTimer )
维护订单,索引就像您在代码中使用ID字段一样。
另一个好的做法是避免使用“id”作为临时变量,因为在wx中有Python内置函数id()AND,小部件也有一个id属性:
w=Widget(..., id=int)
答案 1 :(得分:0)
你做错了,根据this thread,你应该将id参数传递给计时器。对于你的情况,这是我能想到的:
def BuildTimers(self, event):
self.timers = {}
cum_timer = 0
i = 0
for trial in trials:
for timer in timers:
i += 1
key = (timer, trial)
new_timer = wx.Timer(self, id=i)
cum_timer += dm1[screens[timer]]
new_timer.Start(cum_timer * 1000, False)
self.timers[i] = key
self.Bind(wx.EVT_TIMER, lambda event, i=i: self.Screens(event, the_id=i), id=i)
def Screens(self, event, the_id=None):
print "In the timer id =", the_id, "which is", self.timers[the_id]
为什么你做的不起作用
您正在设置Timer实例的属性,然后在您的函数中使用GetEventObject()
。显然,Timer不是一个事件对象......你这样做的方式,所有的计时器都会调用相同的函数而不知道哪一个正在调用它。所以我传递了一个唯一的参数id
,我想这需要一个int。为此,我使用了lambda。它应该工作,但我没有测试它。
另外,正如我看到here,您甚至可能不需要ID,只需将其绑定到计时器,但您可能需要直接将该键作为参数传递。类似的东西(没有i
):
self.Bind(wx.EVT_TIMER, lambda event, k=key: self.Screens(event, the_key=k), new_timer)