2012-11-28 47 views
1

我想使用Python對象作爲Tk帆布項目的包裝。例如:Python的Tk帆布項目事件綁定:遍歷多個項目的綁定

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畫布項目相對應的事件時可以訪問卡片對象。然而,這段代碼的作用是將相同的參數(即卡對象)傳遞給事件處理程序,而不考慮canvas項目。在代碼中,這意味着如果事件順序是點擊,則單擊任何卡片畫布項目都會調用功能event_handler(<last card object in iteration>),而我想單擊畫布項目以調用event_handler(<corresponding card object>)

我有道理嗎?我不明白爲什麼這種方法不會產生我想要的結果。

回答

2

lambda函數中使用帶默認值的可選關鍵字參數。默認值在定義lambda時綁定到lambda,所以在lambdacard是一個局部變量,並且每個lambda對於card將具有不同的默認值。

沒有默認值,當lambda函數被調用時的card值查找使用the LEGB rule - 它看起來在本地,然後擴展,那麼全球,則內建範圍。由於它未在本地範圍內定義,因此它在擴展範圍內(範圍包含for card in [list of cards])。在那裏,card引用list of cards中的最後一張卡片。這就是爲什麼所有點擊事件都會影響同一card

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) 
      ) 
+0

非常感謝!我發現了一個解決方法,但是使用你的解決方案將使我的代碼更容易編寫和減少函數的數量。 – jayhendren