Tkinter:画布结合到事件

时间:2015-09-12 22:43:44

标签: python list canvas tkinter bind

嗨,我有一个非常具体的代码问题,我需要一双新鲜的眼睛来看待。我正在尝试为我编程的奥赛罗游戏制作GUI。我刚开始制作绿色瓷砖,我将玩游戏。为了看到一切正常,我做了一个简单的功能,每次点击其中一个瓷砖时调用。然后该函数应该打印我刚刚单击控制台的磁贴的坐标。但它的作用是打印[7, 7]。这当然是最后创建的瓷砖的坐标。无论如何我不知道我做错了什么,但我的猜测是我不完全理解.bind()函数,谢谢你的帮助。

代码:

from tkinter import *

def print_cors(event, cors):
    print(cors)


class GridFrame:
    def __init__(self, master):
        board = Frame(master, height=500, width=800, bg="brown")
        board.grid()
        self.column_frame_list =  [None]*8
        for x in range(0, len(self.column_frame_list)):
            self.column_frame_list[x] = [None]*8
            for y in range(0, len(self.column_frame_list[x])):
                self.column_frame_list[x][y] = Canvas(board, height=55, width=55, bg="green", bd=0, highlightthickness=0, relief='ridge')
                self.column_frame_list[x][y].bind("<Button-1>", lambda event: print_cors(event, [x,y]))
                self.column_frame_list[x][y].grid(row=y, column=x)

root = Tk()
root.wm_title("Reversi")
grid_frame = GridFrame(root)
root.mainloop()

2 个答案:

答案 0 :(得分:3)

你在函数中尝试过closing x和y吗?

问题是,在循环结束时,函数查找范围中的xy已经更改为7,7。解决方案是创建一个设置所需变量的新范围,并且可以使用返回函数的函数来完成。

尝试更改:

lambda event: print_cors(event, [x,y])

要:

(lambda _x, _y: lambda event: print_cors(event, [_x,_y]))(x,y)

这是你问题的重建:

>>> l = []
>>> for lam in l:
...     print lam()
... 
>>> l = []
>>> for x in range(3):
...     l.append(lambda : x)
... 
>>> for lam in l:
...     print lam()
... 
2
2
2

这是将循环变量装入函数范围(闭包)的解决方案,方法是将它们作为外部函数的参数添加:

>>> l = []
>>> for x in range(3):
...     l.append((lambda _x: lambda : _x)(x)) # close x into the function
... 
>>> for lam in l:
...     print lam()
... 
0
1
2

答案 1 :(得分:1)

通常的解决方案是替换:

self.column_frame_list[x][y].bind("<Button-1>", lambda event: print_cors(event, [x,y]))

使用:

self.column_frame_list[x][y].bind("<Button-1>", lambda event, x=x, y=y: print_cors(event, [x,y]))

请参阅 Tkinter assign button command in loop with lambda

了解更多解释。