Я писал игру Tic-Tac-Toe, используя Tkinter. Когда один пользователь выигрывает, появляется окно Toplevel с кнопкой "Перезагрузить", которое должно перезапустить программу, но я получаю неожиданную ошибку, когда нажимаю на нее. Я знаю, что моя функция проверки победителя глупа, но я мог бы написать лучшую с моим текущим уровнем знаний. Сообщение об ошибке:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\Eldiiar Raiymkulov\AppData\Local\Programs\Python\Python36-32\lib\tkinter\__init__.py", line 1699, in __call__
return self.func(*args)
File "C:\Users\Eldiiar Raiymkulov\Desktop\xo2.py", line 62, in <lambda>
command=lambda x=x, y=y: clicked(y, x)))
File "C:\Users\Eldiiar Raiymkulov\Desktop\xo2.py", line 15, in clicked
isWinner(char)
File "C:\Users\Eldiiar Raiymkulov\Desktop\xo2.py", line 46, in isWinner
topMessage(char)
File "C:\Users\Eldiiar Raiymkulov\Desktop\xo2.py", line 30, in topMessage
topButton = Button(top, text="Restart", command=restart(root))
NameError: name 'root' is not defined
И вот код:
from tkinter import *
turn = True
btns = None
def clicked(y, x):
global turn, btns
char = ""
if turn:
char = "X"
else:
char = "O"
btns[y][x].config(text=char,
state=DISABLED)
isWinner(char)
turn = not turn
def restart(root):
global turn
turn = True
root.destroy()
main()
def topMessage(char):
global root
top = Toplevel()
top.title("Congratulations!")
topText = Label(top, text=f"{char} is a winner!")
topButton = Button(top, text="Restart", command=restart(root))
topText.grid(row=0)
topButton.grid(row=1)
def isWinner(char):
global root
#horizontal
if (((btns[1][1].cget("text") == char) and (btns[1][2].cget("text") == char) and (btns[1][3].cget("text") == char)) or
((btns[2][1].cget("text") == char) and (btns[2][2].cget("text") == char) and (btns[2][3].cget("text") == char)) or
((btns[3][1].cget("text") == char) and (btns[3][2].cget("text") == char) and (btns[3][3].cget("text") == char)) or
#vertical
((btns[1][1].cget("text") == char) and (btns[2][1].cget("text") == char) and (btns[3][1].cget("text") == char)) or
((btns[1][2].cget("text") == char) and (btns[2][2].cget("text") == char) and (btns[3][2].cget("text") == char)) or
((btns[1][3].cget("text") == char) and (btns[2][3].cget("text") == char) and (btns[3][3].cget("text") == char)) or
#diagonal
((btns[1][1].cget("text") == char) and (btns[2][2].cget("text") == char) and (btns[3][3].cget("text") == char)) or
((btns[1][3].cget("text") == char) and (btns[2][2].cget("text") == char) and (btns[3][1].cget("text") == char))):
topMessage(char)
def main():
global btns
root = Tk()
root.title("X and O of Daniar")
root.resizable(False, False)
btns = [None]
for y in range(1, 4):
row = [None]
for x in range(1, 4):
row.append(Button(root,
width=5,
height=3,
font="time 12 bold",
command=lambda x=x, y=y: clicked(y, x)))
row[x].grid(row=y, column=x)
btns.append(row)
Button(root,
text="Restart",
width=5,
command=lambda: restart(root)).grid(row=4, column=2)
root.mainloop()
main()
Кроме того, если у вас есть более разумные предложения по функциям isWinner, не могли бы вы поделиться ими со мной?
Это должно исправить вашу проблему.
Вам нужно было определить переменную вне функций, чтобы использовать ее с глобальным, и чтобы main() использовал эту переменную. Также, если вы вызываете какую-либо функцию в команде и передаете в функцию переменную, всегда используйте лямбду.
from tkinter import *
turn = True
btns = None
root = None
def clicked(y, x):
global turn, btns
char = ""
if turn:
char = "X"
else:
char = "O"
btns[y][x].config(text=char,
state=DISABLED)
isWinner(char)
turn = not turn
def restart(root):
global turn
turn = True
root.destroy()
main()
def topMessage(char):
global root
top = Toplevel()
top.title("Congratulations!")
topText = Label(top, text=f"{char} is a winner!")
topButton = Button(top, text="Restart", command=lambda: restart(root))
topText.grid(row=0)
topButton.grid(row=1)
def isWinner(char):
global root
# horizontal
if (((btns[1][1].cget("text") == char) and (btns[1][2].cget("text") == char) and (btns[1][3].cget("text") == char)) or
((btns[2][1].cget("text") == char) and (btns[2][2].cget("text") == char) and (btns[2][3].cget("text") == char)) or
((btns[3][1].cget("text") == char) and (btns[3][2].cget("text") == char) and (btns[3][3].cget("text") == char)) or
# vertical
((btns[1][1].cget("text") == char) and (btns[2][1].cget("text") == char) and (btns[3][1].cget("text") == char)) or
((btns[1][2].cget("text") == char) and (btns[2][2].cget("text") == char) and (btns[3][2].cget("text") == char)) or
((btns[1][3].cget("text") == char) and (btns[2][3].cget("text") == char) and (btns[3][3].cget("text") == char)) or
# diagonal
((btns[1][1].cget("text") == char) and (btns[2][2].cget("text") == char) and (btns[3][3].cget("text") == char)) or
((btns[1][3].cget("text") == char) and (btns[2][2].cget("text") == char) and (btns[3][1].cget("text") == char))):
topMessage(char)
def main():
global btns
global root
root = Tk()
root.title("X and O of Daniar")
root.resizable(False, False)
btns = [None]
for y in range(1, 4):
row = [None]
for x in range(1, 4):
row.append(Button(root,
width=5,
height=3,
font="time 12 bold",
command=lambda x=x, y=y: clicked(y, x)))
row[x].grid(row=y, column=x)
btns.append(row)
Button(root,
text="Restart",
width=5,
command=lambda: restart(root)).grid(row=4, column=2)
root.mainloop()
main()