Python 特金特的扫雷艇;为什么会发生这种情况?
我正在尝试使用tkinter中的按钮制作扫雷艇,这是我第一次使用tkinter。我唯一的问题是,我不知道如何创建对不同键做出不同反应的按钮(我希望“f”创建一个标志并左键单击“打开”互动程序),同时仍然能够将与创建按钮时不同的变量传递给函数。。。描述将在代码后变得更清晰Python 特金特的扫雷艇;为什么会发生这种情况?,python,python-3.x,variables,tkinter,lambda,Python,Python 3.x,Variables,Tkinter,Lambda,我正在尝试使用tkinter中的按钮制作扫雷艇,这是我第一次使用tkinter。我唯一的问题是,我不知道如何创建对不同键做出不同反应的按钮(我希望“f”创建一个标志并左键单击“打开”互动程序),同时仍然能够将与创建按钮时不同的变量传递给函数。。。描述将在代码后变得更清晰 from tkinter import * from random import * master = Tk() bomb_positions = [] for i in range (
from tkinter import *
from random import *
master = Tk()
bomb_positions = []
for i in range (160):
random = randint(0, 2)
if random == 0 or 1: #These are 'safe' buttons
btn = Button(master, width=2)
btn.bind('<ButtonRelease-1>', lambda event, i=i: check(i))
#Correct value of i when check(i) is called at event
btn.bind('f', lambda event, i=i: place_flag(i))
#Diffrent value if i when place_flag(i) is called at event
btn.pack()
btn.grid(row=row, column=col)
if random == 2: #These are 'bombs'
btn = Button(master, width=2)
btn.bind('<ButtonRelease-1>', function3)
btn.bind('f', lambda event, i=i: place_flag(i)) #Same problem as above
btn.pack()
bomb_positions.append(i)
从tkinter导入*
从随机导入*
master=Tk()
炸弹位置=[]
对于范围(160)内的i:
random=randint(0,2)
如果random==0或1:#这些是“安全”按钮
btn=按钮(主按钮,宽度=2)
绑定(“”,lambda事件,i=i:check(i))
#事件中调用检查(i)时i的正确值
btn.bind('f',lambda事件,i=i:place_标志(i))
#在事件中调用place_标志(i)时,如果i的值不同
btn.pack()
btn.网格(行=行,列=列)
如果随机==2:#这些是“炸弹”
btn=按钮(主按钮,宽度=2)
btn.bind(“”,函数3)
btn.bind('f',lambda事件,i=i:place_flag(i))#与上述问题相同
btn.pack()
炸弹位置。附加(i)
运行程序时,每个按钮的特定值i进入function1。但是,当我在任何按钮上按“f”时,会调用“place_flag()”函数,但i的值不同。(有趣的是,调用“place_flag()”函数时使用的i的值是从不提供任何值开始的。对于tkinter窗口非活动部分上的每次按下TAB,该值从1变为1,每次按下TAB都会增加1。)
我希望I的值与“check()”函数后面的值相同,我不知道是什么导致了我的问题。有什么想法吗
(对于编程非常陌生,很抱歉术语不正确和解释模糊……很高兴能得到所有帮助!)您没有跟踪按钮,因此将来无法编辑它们。我在你的代码中添加了一个btnList来跟踪它们。 我还为
创建了一个新的绑定,该绑定将焦点设置在按钮上,该按钮当前将鼠标置于其上方
此代码应允许您将鼠标悬停在按钮上,按“f”键,按钮文本将从空白变为“f”
我现在还更新了你的代码,这样当用户点击一个方块时,它会检查方块是否在bomb\u位置
列表中;如果是,则在控制台上打印“Boom!!”,并在按钮上放置*号,如果不是炸弹,则在按钮上放置O号
希望我所做的改变能帮助你继续比赛
from tkinter import *
from random import *
master = Tk()
bomb_positions = []
def function3(event):
print("Function3")
def place_flag(square):
print("PlaceFlag")
btnList[square]['text'] = 'F'
def check(square,btn):
print("Check ",square, btn)
if square in bomb_positions:
print("Booommmmm!!!")
btnList[square]['text'] = '*'
else:
btnList[square]['text'] = 'O'
def setFocus(event):
event.widget.focus_set()
btnList = []
for i in range (160):
random = randint(0, 2)
row, col = divmod(i,16)
if random == 0 or 1: #These are 'safe' buttons
btn = Button(master, width=2)
btn.bind('<ButtonRelease-1>', lambda event, i=i: check(i,btn))
#Correct value of i when check(i) is called at event
btn.bind('f', lambda event, i=i: place_flag(i))
#Diffrent value if i when place_flag(i) is called at event
#btn.pack()
btn.grid(row=row, column=col)
if random == 2: #These are 'bombs'
btn = Button(master, width=2)
btn.bind('<ButtonRelease-1>', lambda event, i=i: check(i,btn))
btn.bind('f', lambda event, i=i: place_flag(i)) #Same problem as above
btn.grid(row=row, column=col)
bomb_positions.append(i)
btn.bind("<Enter>",setFocus)
btnList.append(btn)
master.mainloop()
如果您试图用Python实现扫雷器,您可能会发现这是代码的一个有用的起点:
import tkinter
import functools
class MineSweep(tkinter.Frame):
@classmethod
def main(cls, width, height):
root = tkinter.Tk()
window = cls(root, width, height)
root.mainloop()
def __init__(self, master, width, height):
super().__init__(master)
self.__width = width
self.__height = height
self.__build_buttons()
self.grid()
def __build_buttons(self):
self.__buttons = []
for y in range(self.__height):
row = []
for x in range(self.__width):
button = tkinter.Button(self)
button.grid(column=x, row=y)
button['text'] = '?'
command = functools.partial(self.__push, x, y)
button['command'] = command
row.append(button)
self.__buttons.append(row)
def __push(self, x, y):
print('Column = {}\nRow = {}'.format(x, y))
if __name__ == '__main__':
MineSweep.main(10, 10)
如果您正在寻找功能更全面的程序进行修改,您可能希望将此作为起点:
import tkinter
import functools
import random
from tkinter.simpledialog import askstring, Dialog
from tkinter.messagebox import showinfo
import os.path
################################################################################
class MineSweep(tkinter.Frame):
@classmethod
def main(cls, width, height, mines, scores):
root = tkinter.Tk()
root.resizable(False, False)
root.title('MineSweep')
window = cls(root, width, height, mines, scores)
root.protocol('WM_DELETE_WINDOW', window.close)
root.mainloop()
################################################################################
def __init__(self, master, width, height, mines, scores):
super().__init__(master)
self.__width = width
self.__height = height
self.__mines = mines
self.__wondering = width * height
self.__started = False
self.__playing = True
self.__scores = ScoreTable()
self.__record_file = scores
if os.path.isfile(scores):
self.__scores.load(scores)
self.__build_timer()
self.__build_buttons()
self.grid()
def close(self):
self.__scores.save(self.__record_file)
self.quit()
def __build_timer(self):
self.__secs = tkinter.IntVar()
self.__timer = tkinter.Label(textvariable=self.__secs)
self.__timer.grid(columnspan=self.__width, sticky=tkinter.EW)
self.__after_handle = None
def __build_buttons(self):
self.__reset_button = tkinter.Button(self)
self.__reset_button['text'] = 'Reset'
self.__reset_button['command'] = self.__reset
self.__reset_button.grid(column=0, row=1,
columnspan=self.__width, sticky=tkinter.EW)
self.__reset_button.blink_handle = None
self.__buttons = []
for y in range(self.__height):
row = []
for x in range(self.__width):
button = tkinter.Button(self, width=2, height=1,
text='?', fg='red')
button.grid(column=x, row=y+2)
command = functools.partial(self.__push, x, y)
button['command'] = command
row.append(button)
self.__buttons.append(row)
def __reset(self):
for row in self.__buttons:
for button in row:
button.config(text='?', fg='red')
self.__started = False
self.__playing = True
self.__wondering = self.__width * self.__height
if self.__after_handle is not None:
self.after_cancel(self.__after_handle)
self.__after_handle = None
self.__secs.set(0)
def __push(self, x, y, real=True):
button = self.__buttons[y][x]
if self.__playing:
if not self.__started:
self.__build_mines()
while self.__buttons[y][x].mine:
self.__build_mines()
self.__started = True
self.__after_handle = self.after(1000, self.__tick)
if not button.pushed:
self.__push_button(button, x, y)
elif real:
self.__blink(button, button['bg'], 'red')
elif real:
self.__blink(button, button['bg'], 'red')
def __blink(self, button, from_bg, to_bg, times=8):
if button.blink_handle is not None and times == 8:
return
button['bg'] = (to_bg, from_bg)[times & 1]
times -= 1
if times:
blinker = functools.partial(self.__blink, button,
from_bg, to_bg, times)
button.blink_handle = self.after(250, blinker)
else:
button.blink_handle = None
def __tick(self):
self.__after_handle = self.after(1000, self.__tick)
self.__secs.set(self.__secs.get() + 1)
def __push_button(self, button, x, y):
button.pushed = True
if button.mine:
button['text'] = 'X'
self.__playing = False
self.after_cancel(self.__after_handle)
self.__after_handle = None
self.__blink(self.__reset_button, button['bg'], 'red')
else:
button['fg'] = 'SystemButtonText'
count = self.__total(x, y)
button['text'] = count and str(count) or ' '
self.__wondering -= 1
if self.__wondering == self.__mines:
self.after_cancel(self.__after_handle)
self.__after_handle = None
self.__finish_game()
def __finish_game(self):
self.__playing = False
score = self.__secs.get()
for row in self.__buttons:
for button in row:
if button.mine:
button['text'] = 'X'
if self.__scores.eligible(score):
name = askstring('New Record', 'What is your name?')
if name is None:
name = 'Anonymous'
self.__scores.add(name, score)
else:
showinfo('You did not get on the high score table.')
HighScoreView(self, 'High Scores', self.__scores.listing())
def __total(self, x, y):
count = 0
for x_offset in range(-1, 2):
x_index = x + x_offset
for y_offset in range(-1, 2):
y_index = y + y_offset
if 0 <= x_index < self.__width and 0 <= y_index < self.__height:
count += self.__buttons[y_index][x_index].mine
if not count:
self.__propagate(x, y)
return count
def __propagate(self, x, y):
for x_offset in range(-1, 2):
x_index = x + x_offset
for y_offset in range(-1, 2):
y_index = y + y_offset
if 0 <= x_index < self.__width and 0 <= y_index < self.__height:
self.__push(x_index, y_index, False)
def __build_mines(self):
mines = [True] * self.__mines
empty = [False] * (self.__width * self.__height - self.__mines)
total = mines + empty
random.shuffle(total)
iterator = iter(total)
for row in self.__buttons:
for button in row:
button.mine = next(iterator)
button.pushed = False
button.blink_handle = None
################################################################################
class ScoreTable:
def __init__(self, size=10):
self.__data = {999: [''] * size}
def add(self, name, score):
assert self.eligible(score)
if score in self.__data:
self.__data[score].insert(0, name)
else:
self.__data[score] = [name]
if len(self.__data[max(self.__data)]) == 1:
del self.__data[max(self.__data)]
else:
del self.__data[max(self.__data)][-1]
def eligible(self, score):
return score <= max(self.__data)
def listing(self):
for key in sorted(self.__data.keys()):
for name in self.__data[key]:
yield name, key
def load(self, filename):
self.__data = eval(open(filename, 'r').read())
def save(self, filename):
open(filename, 'w').write(repr(self.__data))
################################################################################
class HighScoreView(Dialog):
def __init__(self, parent, title, generator):
self.__scores = generator
super().__init__(parent, title)
def body(self, master):
self.__labels = []
for row, (name, score) in enumerate(self.__scores):
label = tkinter.Label(master, text=name)
self.__labels.append(label)
label.grid(row=row, column=0)
label = tkinter.Label(master, text=str(score))
self.__labels.append(label)
label.grid(row=row, column=1)
self.__okay = tkinter.Button(master, command=self.ok, text='Okay')
self.__okay.grid(ipadx=100, columnspan=2, column=0, row=row+1)
return self.__okay
def buttonbox(self):
pass
################################################################################
if __name__ == '__main__':
MineSweep.main(10, 10, 10, 'scores.txt')
导入tkinter
导入功能工具
随机输入
从tkinter.simpledialog导入askstring,对话框
从tkinter.messagebox导入showinfo
导入操作系统路径
################################################################################
类扫雷(tkinter.Frame):
@类方法
def干管(cls、宽度、高度、地雷、分数):
root=tkinter.Tk()
根目录。可调整大小(False,False)
root.title(‘扫雷’)
窗口=cls(根、宽度、高度、矿山、分数)
root.protocol('WM\u DELETE\u WINDOW',WINDOW.close)
root.mainloop()
################################################################################
定义初始(自我、主控、宽度、高度、地雷、分数):
超级()。\uuuu初始化\uuuuu(主)
自身宽度=宽度
自身高度=高度
自我保护地雷=地雷
self.\uu=宽度*高度
self.\uuu start=False
self.\uu playing=True
self.\uuu分数=分数表()
自我记录文件=分数
如果os.path.isfile(分数):
自我。分数。加载(分数)
self.\u构建\u计时器()
self.\u构建按钮()
self.grid()
def关闭(自我):
self.\u scores.save(self.\u record\u文件)
self.quit()
定义生成计时器(自身):
self.\uu secs=tkinter.IntVar()
self.\uuu timer=tkinter.Label(textvariable=self.\uu secs)
self.\uuu timer.grid(columnspan=self.\uu width,sticky=tkinter.EW)
self.\u在\u句柄之后=无
def u构建按钮(自):
self.\uuu重置\u按钮=tkinter.按钮(self)
self.\u重置按钮['text']=“重置”
自复位按钮['command']=自复位
self.\u重置按钮.grid(列=0,行=1,
columnspan=self.\uu宽度,sticky=tkinter.EW)
self.\u重置\u按钮。闪烁\u手柄=无
self._按钮=[]
对于范围内的y(自身高度):
行=[]
对于范围内的x(自身宽度):
按钮=tkinter.按钮(自身,宽度=2,高度=1,
text=“?”,fg=”红色“)
按钮网格(列=x,行=y+2)
command=functools.partial(self.\u push,x,y)
按钮['command']=命令
行。追加(按钮)
self.\u按钮.附加(行)
def___重置(自):
对于“自”按钮中的行:
对于行中的按钮:
button.config(文本=“?”,fg=”红色“)
self.\uuu start=False
self.\uu playing=True
self.\uuu=self.\uu宽度*self.\uu高度
如果句柄后的self.\u不是None:
self.after\u取消(self.\u after\u句柄)
self.\u在\u句柄之后=无
自我设置(0)
定义推送(自、x、y、真实)=
import tkinter
import functools
import random
from tkinter.simpledialog import askstring, Dialog
from tkinter.messagebox import showinfo
import os.path
################################################################################
class MineSweep(tkinter.Frame):
@classmethod
def main(cls, width, height, mines, scores):
root = tkinter.Tk()
root.resizable(False, False)
root.title('MineSweep')
window = cls(root, width, height, mines, scores)
root.protocol('WM_DELETE_WINDOW', window.close)
root.mainloop()
################################################################################
def __init__(self, master, width, height, mines, scores):
super().__init__(master)
self.__width = width
self.__height = height
self.__mines = mines
self.__wondering = width * height
self.__started = False
self.__playing = True
self.__scores = ScoreTable()
self.__record_file = scores
if os.path.isfile(scores):
self.__scores.load(scores)
self.__build_timer()
self.__build_buttons()
self.grid()
def close(self):
self.__scores.save(self.__record_file)
self.quit()
def __build_timer(self):
self.__secs = tkinter.IntVar()
self.__timer = tkinter.Label(textvariable=self.__secs)
self.__timer.grid(columnspan=self.__width, sticky=tkinter.EW)
self.__after_handle = None
def __build_buttons(self):
self.__reset_button = tkinter.Button(self)
self.__reset_button['text'] = 'Reset'
self.__reset_button['command'] = self.__reset
self.__reset_button.grid(column=0, row=1,
columnspan=self.__width, sticky=tkinter.EW)
self.__reset_button.blink_handle = None
self.__buttons = []
for y in range(self.__height):
row = []
for x in range(self.__width):
button = tkinter.Button(self, width=2, height=1,
text='?', fg='red')
button.grid(column=x, row=y+2)
command = functools.partial(self.__push, x, y)
button['command'] = command
row.append(button)
self.__buttons.append(row)
def __reset(self):
for row in self.__buttons:
for button in row:
button.config(text='?', fg='red')
self.__started = False
self.__playing = True
self.__wondering = self.__width * self.__height
if self.__after_handle is not None:
self.after_cancel(self.__after_handle)
self.__after_handle = None
self.__secs.set(0)
def __push(self, x, y, real=True):
button = self.__buttons[y][x]
if self.__playing:
if not self.__started:
self.__build_mines()
while self.__buttons[y][x].mine:
self.__build_mines()
self.__started = True
self.__after_handle = self.after(1000, self.__tick)
if not button.pushed:
self.__push_button(button, x, y)
elif real:
self.__blink(button, button['bg'], 'red')
elif real:
self.__blink(button, button['bg'], 'red')
def __blink(self, button, from_bg, to_bg, times=8):
if button.blink_handle is not None and times == 8:
return
button['bg'] = (to_bg, from_bg)[times & 1]
times -= 1
if times:
blinker = functools.partial(self.__blink, button,
from_bg, to_bg, times)
button.blink_handle = self.after(250, blinker)
else:
button.blink_handle = None
def __tick(self):
self.__after_handle = self.after(1000, self.__tick)
self.__secs.set(self.__secs.get() + 1)
def __push_button(self, button, x, y):
button.pushed = True
if button.mine:
button['text'] = 'X'
self.__playing = False
self.after_cancel(self.__after_handle)
self.__after_handle = None
self.__blink(self.__reset_button, button['bg'], 'red')
else:
button['fg'] = 'SystemButtonText'
count = self.__total(x, y)
button['text'] = count and str(count) or ' '
self.__wondering -= 1
if self.__wondering == self.__mines:
self.after_cancel(self.__after_handle)
self.__after_handle = None
self.__finish_game()
def __finish_game(self):
self.__playing = False
score = self.__secs.get()
for row in self.__buttons:
for button in row:
if button.mine:
button['text'] = 'X'
if self.__scores.eligible(score):
name = askstring('New Record', 'What is your name?')
if name is None:
name = 'Anonymous'
self.__scores.add(name, score)
else:
showinfo('You did not get on the high score table.')
HighScoreView(self, 'High Scores', self.__scores.listing())
def __total(self, x, y):
count = 0
for x_offset in range(-1, 2):
x_index = x + x_offset
for y_offset in range(-1, 2):
y_index = y + y_offset
if 0 <= x_index < self.__width and 0 <= y_index < self.__height:
count += self.__buttons[y_index][x_index].mine
if not count:
self.__propagate(x, y)
return count
def __propagate(self, x, y):
for x_offset in range(-1, 2):
x_index = x + x_offset
for y_offset in range(-1, 2):
y_index = y + y_offset
if 0 <= x_index < self.__width and 0 <= y_index < self.__height:
self.__push(x_index, y_index, False)
def __build_mines(self):
mines = [True] * self.__mines
empty = [False] * (self.__width * self.__height - self.__mines)
total = mines + empty
random.shuffle(total)
iterator = iter(total)
for row in self.__buttons:
for button in row:
button.mine = next(iterator)
button.pushed = False
button.blink_handle = None
################################################################################
class ScoreTable:
def __init__(self, size=10):
self.__data = {999: [''] * size}
def add(self, name, score):
assert self.eligible(score)
if score in self.__data:
self.__data[score].insert(0, name)
else:
self.__data[score] = [name]
if len(self.__data[max(self.__data)]) == 1:
del self.__data[max(self.__data)]
else:
del self.__data[max(self.__data)][-1]
def eligible(self, score):
return score <= max(self.__data)
def listing(self):
for key in sorted(self.__data.keys()):
for name in self.__data[key]:
yield name, key
def load(self, filename):
self.__data = eval(open(filename, 'r').read())
def save(self, filename):
open(filename, 'w').write(repr(self.__data))
################################################################################
class HighScoreView(Dialog):
def __init__(self, parent, title, generator):
self.__scores = generator
super().__init__(parent, title)
def body(self, master):
self.__labels = []
for row, (name, score) in enumerate(self.__scores):
label = tkinter.Label(master, text=name)
self.__labels.append(label)
label.grid(row=row, column=0)
label = tkinter.Label(master, text=str(score))
self.__labels.append(label)
label.grid(row=row, column=1)
self.__okay = tkinter.Button(master, command=self.ok, text='Okay')
self.__okay.grid(ipadx=100, columnspan=2, column=0, row=row+1)
return self.__okay
def buttonbox(self):
pass
################################################################################
if __name__ == '__main__':
MineSweep.main(10, 10, 10, 'scores.txt')