Tkinter:画布绑定到事件
Tkinter: Canvases Binded to Events
您好,我有一个非常具体的代码问题,我需要一双新的眼睛来审视。我正在尝试为我编写的 Othello 游戏制作 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()
您在函数中尝试过 closing x 和 y 吗?
问题是函数查找范围内的 x
和 y
在循环结束时已经更改为 7, 7。解决方案是在设置所需变量的地方创建一个新范围,并且可以使用 returns 一个函数的函数来完成。
尝试更改:
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
通常的解决方案是替换:
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
更多解释。
您好,我有一个非常具体的代码问题,我需要一双新的眼睛来审视。我正在尝试为我编写的 Othello 游戏制作 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()
您在函数中尝试过 closing x 和 y 吗?
问题是函数查找范围内的 x
和 y
在循环结束时已经更改为 7, 7。解决方案是在设置所需变量的地方创建一个新范围,并且可以使用 returns 一个函数的函数来完成。
尝试更改:
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
通常的解决方案是替换:
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
更多解释。