在循环中创建按钮时,我们可以创建(实际获得)唯一标识。
例如:如果我们创建一个按钮:
button = Button(master, text="text")
我们可以立即识别它:
print(button)
> <tkinter.Button object .140278326922376>
如果我们将此标识存储到一个列表中,并将命令分配给按钮,在创建期间链接到它们的索引,我们可以在按下时获取它们的特定标识。
我们唯一要做的就是在按下按钮后通过索引获取按钮的标识。
为了能够以索引为参数为按钮设置命令,我们使用functools'partial。
简化示例 (python3)
在下面的简化示例中,我们循环创建按钮,将它们的标识添加到列表中 (button_identities)。身份是通过以下方式查找的:bname = (button_identities[n])。
现在我们有了身份,我们可以随后让按钮做任何事情,包括编辑或杀死自己,因为我们有了它的身份。
在下面的示例中,按下按钮会将其标签更改为“已单击”
from tkinter import *
from functools import partial
win = Tk()
button_identities = []
def change(n):
# function to get the index and the identity (bname)
print(n)
bname = (button_identities[n])
bname.configure(text = "clicked")
for i in range(5):
# creating the buttons, assigning a unique argument (i) to run the function (change)
button = Button(win, width=10, text=str(i), command=partial(change, i))
button.pack()
# add the button's identity to a list:
button_identities.append(button)
# just to show what happens:
print(button_identities)
win.mainloop()
或者如果我们让它销毁按钮一旦被点击:
from tkinter import *
from functools import partial
win = Tk()
button_identities = []
def change(n):
# function to get the index and the identity (bname)
print(n)
bname = (button_identities[n])
bname.destroy()
for i in range(5):
# creating the buttons, assigning a unique argument (i) to run the function (change)
button = Button(win, width=10, text=str(i), command=partial(change, i))
button.place(x=0, y=i*30)
# add the button's identity to a list:
button_identities.append(button)
# just to show what happens:
print(button_identities)
win.mainloop()
矩阵的简化代码 (python3):
在下面的示例中,我使用itertools's product() 来生成矩阵的坐标。
#!/usr/bin/env python3
from tkinter import *
from functools import partial
from itertools import product
# produce the set of coordinates of the buttons
positions = product(range(10), range(10))
button_ids = []
def change(i):
# get the button's identity, destroy it
bname = (button_ids[i])
bname.destroy()
win = Tk()
frame = Frame(win)
frame.pack()
for i in range(10):
# shape the grid
setsize = Canvas(frame, width=30, height=0).grid(row=11, column=i)
setsize = Canvas(frame, width=0, height=30).grid(row=i, column=11)
for i, item in enumerate(positions):
button = Button(frame, command=partial(change, i))
button.grid(row=item[0], column=item[1], sticky="n,e,s,w")
button_ids.append(button)
win.minsize(width=270, height=270)
win.title("Too many squares")
win.mainloop()
更多选项,按坐标销毁按钮
由于product() 也产生按钮的x,y 坐标,我们可以额外存储坐标(在示例中为coords),并通过坐标识别按钮的身份。
在下面的例子中,函数hide_by_coords():通过坐标破坏按钮,这在minesweeper类游戏中很有用。例如,单击一个按钮也会破坏右侧的按钮:
#!/usr/bin/env python3
from tkinter import *
from functools import partial
from itertools import product
positions = product(range(10), range(10))
button_ids = []; coords = []
def change(i):
bname = (button_ids[i])
bname.destroy()
# destroy another button by coordinates
# (next to the current one in this case)
button_nextto = coords[i]
button_nextto = (button_nextto[0] + 1, button_nextto[1])
hide_by_coords(button_nextto)
def hide_by_coords(xy):
# this function can destroy a button by coordinates
# in the matrix (topleft = (0, 0). Argument is a tuple
try:
index = coords.index(xy)
button = button_ids[index]
button.destroy()
except (IndexError, ValueError):
pass
win = Tk()
frame = Frame(win)
frame.pack()
for i in range(10):
# shape the grid
setsize = Canvas(frame, width=30, height=0).grid(row=11, column=i)
setsize = Canvas(frame, width=0, height=30).grid(row=i, column=11)
for i, item in enumerate(positions):
button = Button(frame, command=partial(change, i))
button.grid(column=item[0], row=item[1], sticky="n,e,s,w")
button_ids.append(button)
coords.append(item)
win.minsize(width=270, height=270)
win.title("Too many squares")
win.mainloop()