2010-11-21 36 views
3

異なることをするn個のTkinterボタンを生成したい。 boardWidthが5であれば、私がクリックしたとき、彼らはすべてBoard.playColumn(5、Board.getCurrentPlayer())を行う1-5ラベル付きボタンを取得するのに、動的にTkinterボタンを生成する

import Tkinter as tk 

for i in range(boardWidth): 
    newButton = tk.Button(root, text=str(i+1), 
     command=lambda: Board.playColumn(i+1, Board.getCurrentPlayer())) 
    Board.boardButtons.append(newButton) 

:私はこのコードを持っています。

Board.playColumn(1、Board.getCurrentPlayer())を実行するための最初のボタン、Board.playColumn(2、Board.getCurrentPlayer())を実行する2番目のボタンなどが必要です。

ありがとうございました!

答えて

8

私はこの問題は、lambdaforループ終了後iの最終値を拾っているということだと思います。これは、(未テスト)を修正する必要があります。

import Tkinter as tk 

for i in range(boardWidth): 
    newButton = tk.Button(root, text=str(i+1), 
     command=lambda j=i+1: Board.playColumn(j, Board.getCurrentPlayer())) 
    Board.boardButtons.append(newButton) 

更新ところで

、これはそれがなく、作成されたときiの値から算出したデフォルト値を持つlambda関数に引数を追加することによって、働いていましたその内部の式が後で実行されるときにクロージャを介してiの最終値を参照します。

+0

うん、それはうまくいった。ありがとう! – rikkit

2

あなたの問題は、同じ名前空間内に多くのlambdaオブジェクトを作成し、それらのlambdaが外側スコープ内の名前を参照することです。つまり、クロージャにならず、オブジェクトへの参照が後で保存されることはありません。発生すると、すべてのラムダは、最後の値であるiを参照します。

それを修正するためのコールバックの工場を使用してみてください:

import Tkinter as tk 

def callbackFactory(b, n): 
    def _callback(): 
     return b.playColumn(n, b.getCurrentPlayer()) 
    return _callback 

for i in range(boardWidth): 
    newButton = tk.Button(root, text=str(i+1), 
     command=callbackFactory(Board, i+1)) 
    Board.boardButtons.append(newButton) 

もう一つのアイデアは、代わりに参照を格納するための閉鎖動作に依存するので、lambdaオブジェクトのデフォルト引数の値として、iの現在の値を格納することです:

for i in range(boardWidth): 
    newButton = tk.Button(root, text=str(i+1), 
     command=lambda x=i: Board.playColumn(x+1, Board.getCurrentPlayer())) 
    Board.boardButtons.append(newButton) 
+0

martineauの提案に従って、2番目の例を試してみてください。なぜこれが起こったのかを説明してくれてありがとう! – rikkit

関連する問題