我收到错误_tkinter.TclError:错误的窗口路径名称"。!button"而且我不确定为什么

时间:2018-04-13 22:22:23

标签: python oop tkinter

我决定尝试使用类来重新创建一个游戏,这样我就不必使用全局变量,但是当我尝试运行游戏时,我收到错误。

Traceback (most recent call last):  File "D:\Users\James\Desktop\botmod OOP\index.py", line 203, in <module>    Game.New_Game(Root)  File "D:\Users\James\Desktop\botmod OOP\index.py", line 18, in New_Game    Play_Button = self.Start_Canvas.create_window(300, 325, window = Play_Button)  File "C:\Users\James\AppData\Local\Programs\Python\Python36\lib\tkinter\__init__.py">, line 2501, in create_window    return self._create('window', args, kw)  File "C:\Users\James\AppData\Local\Programs\Python\Python36\lib\tkinter\__init__.py">, line 2474, in _create    *(args + self._options(cnf, kw))))
_tkinter.TclError: bad window path name ".!button"

我已尽最大努力了解这一点,并且不能单独锻炼错误是什么。下面是我的代码我可以提供所有代码,如果需要只是评论。它应该创建一个Tkinter按钮,然后将其应用到画布,但它给我上面的错误。

def New_Game(self, Root):        
    self.Start_Canvas = Canvas(Root, width = 600, height = 500, bd=0, highlightthickness=0, bg = '#ffffff')
    self.Start_Canvas.pack()

    Title = self.Start_Canvas.create_text(300, 163, text = "BOTMOD", font = ('Cinema Gothic BTN Shadow', 75, 'normal'))

    Gen_PButton = Button(text = "PLAY", width = 10, font=('Arial', 15), command = self.Play_Game)
    Play_Button = self.Start_Canvas.create_window(300, 325, window = Gen_PButton)

    Gen_EButton = Button(text = "EXIT", width = 10, font=('Arial', 15), command = lambda: self.Game_End("EXIT"))
    Exit_Button = self.Start_Canvas.create_window(300, 375, window = Gen_EButton)

在我使用oop之前,这使用了全局变量和函数,因此在定义按钮时找不到导致问题的原因。

示例代码位于

之下
from tkinter import *
from random import choice, shuffle

class Game:
    def __init__(self):
        self.Playing_Game = True
        self.Game_Paused = False
        self.Restart_Game = False
        self.Already_Played = False

    def New_Game(self, Root):        
        self.Start_Canvas = Canvas(Root, width = 600, height = 500, bd=0, highlightthickness=0, bg = '#ffffff')
        self.Start_Canvas.pack()

        Title = self.Start_Canvas.create_text(300, 163, text = "BOTMOD", font = ('Cinema Gothic BTN Shadow', 75, 'normal'))

        Gen_PButton = Button(text = "PLAY", width = 10, font=('Arial', 15), command = self.Play_Game)
        Play_Button = self.Start_Canvas.create_window(300, 325, window = Gen_PButton)

        Gen_EButton = Button(text = "EXIT", width = 10, font=('Arial', 15), command = lambda: self.Game_End("EXIT"))
        Exit_Button = self.Start_Canvas.create_window(300, 375, window = Gen_EButton)

    def Play_Game(self):
        if self.Already_Played == False:
            self.Start_Canvas.destroy()
        self.Menu_Canvas = Canvas(Root, width = 600, height = 500, bd=0, highlightthickness=0, bg = '#C0C0C0')
        self.Menu_Canvas.pack()

    def Game_End(self):
        if self.End_Option == "EXIT":
            self.Playing_Game = False
            Root.destroy()
        else:
            self.Game_Finished = True
            self.Game_Canvas.create_rectangle(120, 120, 480, 300, fill = "#ffffff")
            self.Game_Canvas.create_text(300, 210, text = End_Option, font = ('Abadi', 35, "bold"))
            #Continue_Button = Button(Root, text = 'Continue', command = self.Game_Restart)
            Exit_Button = Button(Root, text = 'Exit', command = lambda: self.Game_End('EXIT'))
            #Continue_Button.pack()
            Exit_Button.pack()

Root = Tk()
Game = Game()

while True:
    while Game.Restart_Game == False:
        if Game.Playing_Game == False:
            break
        else:
            Game_Finished = False
            Root = Tk()
            if Game.Already_Played == True:
                Game.Play_Game()
                Root.mainloop()
            elif Game.Already_Played == False:
                Game.New_Game(Root)
                Root.mainloop()
    break

1 个答案:

答案 0 :(得分:2)

当前的问题是你没有给父母按钮。 tl; dr是您只需要将Root(或其他一些适当的父窗口)添加到Gen_PbuttonGen_EButton的构造函数中,就像对所有其他小部件一样。

以下两行有重要区别:

Gen_PButton = Button(Root, text = "PLAY", width = 10, font=('Arial', 15), command = self.Play_Game)
Gen_PButton = Button(text = "PLAY", width = 10, font=('Arial', 15), command = self.Play_Game)

两个版本都为按钮小部件创建了一个新名称(在本例中为.!button),并创建了一个与该名称相关联的新tkinter.Button对象 - 但第一个也要求Root创建名为.!button的实际窗口小部件,而第二个窗口小部件不要求任何人创建窗口小部件。因此,您最终会得到一个附加到不存在的窗口小部件的Button对象,并且每当您尝试使用该Button对象时,都会出现如下错误:

_tkinter.TclError: bad window path name ".!button"

此类错误的常见原因是您已销毁基础按钮小部件但仍尝试使用Button。但在这种情况下,您从未创建过小部件,这显然会导致同样的问题。

要准确了解幕后的内容,您必须了解Tkinter的工作原理 - 实际的GUI小部件和窗口由代码以完全不同的语言管理,Tcl / Tk和tkinter是与Tcl对象关联的Python对象按名称并代理对这些Tcl对象的每个方法调用。

你可能想知道为什么tkinter会让你首先摆脱这种结构,而不是给你一个更容易理解的错误,更早一行,就像这样:

_tkinter.TclError: trying to create ".!button" with null parent

嗯,从技术上讲,这是完全合法的。您可以稍后通过某种较低级别的方法创建该Tcl小部件,或者您可能已经创建了该Tcl小部件,现在只想将tkinter控制器包裹起来。两者都是非常罕见的情况,但它们并非荒谬,所以tkinter允许它们。

而且,更重要的是:您是否真的更容易理解“更好”的错误消息?当你第一次学习tkinter时,两者都没有意义,而且这两件事都是你可以学会理解和处理的事情。