1

TkキャンバスアイテムのラッパーとしてPythonオブジェクトを使用しようとしています。例えば:

class PlayingCard:
    def __init__(self, item):
        self.item = item

aceOfSpades = PlayingCard(canvas.create_image((coordinates), image = PhotoImage(aceofspades.gif)))
print aceOfSpades.item
>>> <canvas item id>

このようにして、キャンバスアイテムを操作する必要がある場合、オブジェクトによってそれを参照できます。

aceOfSpades.item.move(dx, dy)

したがって、問題は、多くのオブジェクト(実際には52)があり、それぞれがキャンバスイメージアイテムを参照する独自のself.itemを持っていることです。オブジェクトを反復処理して、キャンバスアイテムのイベントバインディングを作成したい場合オブジェクトは特定の条件を満たす。これが私の解決策です(疑似pycode):

def event_handler(card):
    card.attribute = updated_value

for card in [list of card objects]:
    if card.attribute == test_condition:
        canvas.tag_bind(
            card.item, #this is the item id stored in the PlayingCard.item variable
            <Event Sequence>,
            lambda x: event_handler(card)
            )

問題は、反復が完了した後、すべてのイベントバインディングが同じ引数をイベントハンドラーに渡すことです。

つまり、カードオブジェクトを引数としてイベントハンドラーに渡し、カードのobject.itemキャンバスアイテムに対応するイベントが発生したときにイベントハンドラーがカードオブジェクトにアクセスできるようにしたかったのです。ただし、このコードが代わりに行うことは、キャンバスアイテムに関係なく、同じ引数(つまりカードオブジェクト)をイベントハンドラーに渡すことです。コードでは、これは、イベントシーケンスがクリックの場合、カードキャンバスアイテムをクリックすると関数が呼び出されるのevent_handler(<last card object in iteration>)に対し、キャンバスアイテムをクリックして呼び出すことを意味しますevent_handler(<corresponding card object>)

私は理にかなっていますか?このアプローチで希望する結果が得られない理由がわかりません。

4

1 に答える 1

2

関数でデフォルト値を持つオプションのキーワード引数を使用しますlambda。デフォルト値は、ラムダが定義された時点でラムダにバインドされているため、内にlambdacardローカル変数があり、各ラムダは。に対して異なるデフォルト値を持ちますcard

デフォルト値がない場合、lambda関数が呼び出されると、の値はLEGBルールcardを使用して検索されます。つまり、ローカル、拡張、グローバル、ビルトインの順にスコープで検索されます。ローカルスコープで定義されていないため、拡張スコープ(を含むスコープ)で検出されます。そこでは、の最後のカードを参照します。これが、すべてのクリックイベントが同じに影響を与える理由です。for card in [list of cards]cardlist of cardscard

for card in [list of card objects]:
    if card.attribute == test_condition:
        canvas.tag_bind(
            card.item, #this is the item id stored in the PlayingCard.item variable
            <Event Sequence>,
            lambda x, card = card: event_handler(card)
            )
于 2012-11-28T18:07:49.733 に答える