Tkinter和井字游戏的麻烦

时间:2018-12-08 17:11:27

标签: python tkinter

我正在用Tkinter编写井字游戏。当一个用户获胜时,将出现一个带有“重新启动”按钮的“顶层”窗口,该窗口必须重新启动该程序,但是单击该程序时会收到意外错误。我知道我的获胜者检查功能很愚蠢,但是我可以根据当前的知识水平编写更好的软件。 错误消息:

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功能有更明智的建议,可以与我分享吗?

1 个答案:

答案 0 :(得分:1)

这应该可以解决您的问题。

您需要在函数外部定义一个变量,以将其与global一起使用,并让main()使用该变量。另外,如果要在命令中调用任何函数并将变量传递给该函数,请始终使用lambda。

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()