我正在尝试使用tkinter在python上编写扫雷游戏。我开始时使用10x10的二维列表创建一个按钮网格。然后我使用循环创建了每个按钮,因此我不必手动创建每个按钮并将其剪辑。
self.b=[[0 for x in range(1,12)] for y in range(1,12)] #The 2 dimensional list
for self.i in range(1,11):
for self.j in range(1,11):
self.b[self.i][self.j]=tkinter.Button(root,text = (" "),command = lambda: self.delete()) # creating the button
self.b[self.i][self.j].place(x=xp,y=yp) # placing the button
xp+=26 #because the width and height of the button is 26
yp+=26
xp=0
基本上我希望按钮在按下时消失。问题是我不知道如何让程序专门删除我按下的按钮,因为所有按钮完全相同。创建删除功能时:
def delete(self):
self.b[???][???].destroy()
我不知道如何让程序知道用户按下哪个按钮,因此可以删除该特定按钮。
问题: 有没有办法让每个按钮都有一些独特的东西,可以区别于其他按钮?比如给每个按钮分配一个特定的坐标,所以当按下按钮(2,3)时,数字2和3被传递到删除功能,所以删除功能可以删除按钮(2,3)?
答案 0 :(得分:4)
在循环中创建按钮时,我们可以创建(实际获得)唯一标识。
例如:如果我们创建一个按钮:
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()
在下面的示例中,我使用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
),并通过坐标识别按钮的标识。 / p>
在下面的示例中,函数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()
答案 1 :(得分:2)
如果您只想销毁Button小部件,那么简单的方法是在创建按钮后添加回调。例如,
import Tkinter as tk
grid_size = 10
root = tk.Tk()
blank = " " * 3
for y in range(grid_size):
for x in range(grid_size):
b = tk.Button(root, text=blank)
b.config(command=b.destroy)
b.grid(column=x, row=y)
root.mainloop()
但是,如果您需要在回调中进行额外处理,例如更新按钮网格,则可以方便地将Button的网格索引存储为Button对象的属性。
from __future__ import print_function
import Tkinter as tk
class ButtonDemo(object):
def __init__(self, grid_size):
self.grid_size = grid_size
self.root = tk.Tk()
self.grid = self.button_grid()
self.root.mainloop()
def button_grid(self):
grid = []
blank = " " * 3
for y in range(self.grid_size):
row = []
for x in range(self.grid_size):
b = tk.Button(self.root, text=blank)
b.config(command=lambda widget=b: self.delete_button(widget))
b.grid(column=x, row=y)
#Store row and column indices as a Button attribute
b.position = (y, x)
row.append(b)
grid.append(row)
return grid
def delete_button(self, widget):
y, x = widget.position
print("Destroying", (y, x))
widget.destroy()
#Mark this button as invalid
self.grid[y][x] = None
ButtonDemo(grid_size=10)
这两个脚本都与Python 3兼容,只需将导入行更改为
即可import tkinter as tk
答案 2 :(得分:1)
尝试按以下方式修改代码:
self.b=[[0 for x in range(10)] for y in range(10)] #The 2 dimensional list
xp = yp = 0
for i in range(10):
for j in range(10):
self.b[i][j]=tkinter.Button(root,text=" ",command=lambda i=i,j=j: self.delete(i,j)) # creating the button
self.b[i][j].place(x=xp,y=yp) # placing the button
xp+=26 #because the width and height of the button is 26
yp+=26
xp=0
和
def delete(self, i, j):
self.b[i][j].destroy()
答案 3 :(得分:0)
以下代码在每行中生成12个按钮,4。 需要编辑的特定按钮的调用类似于调用矩阵元素。作为示例,按钮[1,1]已被编辑为背景色,按钮[2,2]已被编辑为前景色和文本。该程序已在python3.6 pycharm控制台上进行了测试
from tkinter import *
root=Tk()
Buts={}
for r in range(3):
for c in range(4):
Buts[(r,c)]=Button(root,text='%s/%s'%(r,c),borderwidth=10)
Buts[r,c].grid(row=r,column=c)
Buts[1,1]['bg']='red'
Buts[2,2]['text']=['BUTTON2']
Buts[2,2]['fg']=['blue']
root.mainloop()
答案 4 :(得分:0)
有一种方法可以将参数传递给按下按钮时执行的函数:
from tkinter import *
from functools import partial
root = Tk()
root.geometry("300x200")
b = Button(root, text = "some text", command=partial(yourfunc, argument))
b.pack()
root.mainloop()