0

forループでn個のタイマーを作成して初期化し、それらをいくつかのイベントにバインドするPythonコードを作成しようとしています。以下のコードは、私が行っている方法の例です。

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()

指定した時間にタイマーが開始されません。2 番目のループが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ますが、タイマーをイベントにバインドするより良い方法がわかりません。誰かがアイデアを持っていますか?

どうもありがとう!

4

2 に答える 2

1

wxPythonを使用する場合、ウィジェットがデフォルトのパラメーターを使用して独自のIDを生成できるようにする方が賢明だと思います。次に、ウィジェットにウィジェットIDを要求するだけです。手動のマジックナンバーID値を使用して、ウィジェットのID値をそれに送信することは危険な方法であり、デバッグが非常に難しいことを意味します。特に、低範囲で定義済みの束があるため、4000未満のIDの場合はそうです。一部の内部メソッドは、たとえば「id 1のウィジェットをくれ」と要求し、内部のデフォルトウィジェットを取得する代わりに、そのメソッドは代わりにタイマーウィジェットを取得します。

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フィールドを使用した方法と同じように機能します。

もう1つの良い方法は、Pythonの組み込み関数id()があり、wxにはウィジェットにもid属性があるため、一時変数として「id」を使用しないようにすることです。

w=Widget(..., id=int)
于 2012-06-23T19:42:56.800 に答える
0

このスレッドによると、あなたは間違っています.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である必要がある一意のパラメータを渡しました。そのために、ラムダを使用しました。動作するはずですが、テストはしていません。

また、ここで見たように、id さえ必要なく、タイマーにバインドするだけで、キーをパラメーターとして直接渡す必要がある場合があります。のようなもの (なしi):

self.Bind(wx.EVT_TIMER, lambda event, k=key: self.Screens(event, the_key=k), new_timer)

于 2012-06-22T23:02:49.597 に答える