_tkinter.TclError: can't invoke "update" command: application has been destroyed error

_tkinter.TclError: can't invoke "update" command: application has been destroyed error

我有以下代码,在我在程序末尾添加 while 循环之前工作正常,它基本上寻求保持循环 运行ning 永远(更新屏幕)直到 window 已关闭。

 while 1:
        tk.update_idletasks()
        tk.update()
        time.sleep(0.01)

将上述代码添加到现有代码后,程序 运行s,但在退出时...出现此 错误:

_tkinter.TclError: can't invoke "update" command: application has been destroyed error

我在 SO 上看到过类似的问题,但是 none 对于这个特定问题和 none 的答案可能对我的具体情况有所帮助。

完整代码如下:

Question/Problem: 是什么导致了这个错误,我该如何解决?

from tkinter import *
import random
import time
tk=Tk()
tk.title("My 21st Century Pong Game")
tk.resizable(0,0)
tk.wm_attributes("-topmost",1)
canvas=Canvas(tk,bg="white",width=500,height=400,bd=0,highlightthickness=0)
canvas.pack()
tk.update()


class Ball: #create a ball class
    def __init__(self,canvas,color): #initiliased with the variables/attributes self, canvas, and color
        self.canvas=canvas #set the intiial values for the starting attributes
        self.id=canvas.create_oval(30,30,50,50,fill=color) #starting default values for the ball
        """ Note: x and y coordinates for top left corner and x and y coordinates for the bottom right corner, and finally the fill colour for the oval
        """
        self.canvas.move(self.id,0,0) #this moves the oval to the specified location

    def draw(self): #we have created the draw method but it doesn't do anything yet.
        pass 


ball1=Ball(canvas,'green') #here we are creating an object (green ball) of the class Ball

while 1:
    tk.update_idletasks()
    tk.update()
    time.sleep(0.01)

说明更新:

另外值得说明的是:

主循环是程序的核心部分,IDLE 已经有一个主循环 - 但是如果你 运行 这个程序在 IDLE 之外,canvas 会出现然后消失一瞬间。为了阻止 window 关闭,我们需要一个动画循环 - 因此 while 1: ..... 否则,正如用户在下面评论的那样,我们不需要 while 1: 因为 IDLE 已经有了这个就位(它在 IDLE 中工作正常,无需使用 while 1:..etc)

您实际上是在尝试实现自己的 mainloop 而不是使用它。

要了解mainloop,可以阅读一下。您可以将其视为您添加的新代码的语法抽象;你的 while 循环。您几乎是在尝试通过自己循环 "update the screen" 来重新创建轮子,而当轮子已经存在时!

退出程序时,使用sys.exit().

可以避免错误

编辑:

替换以下代码:

while 1:
    tk.update_idletasks()
    tk.update()
    time.sleep(0.01)

有了这个:

tk.mainloop()

你的错误是因为,正如它所说,如果 window 已被销毁,你将无法更新它。 mainloop 应该处理这个问题。

当您退出您的应用程序时,下次您调用 update_idletasks 时,window 对象将被销毁。然后您尝试在不存在的 window 上调用 update

您需要删除所有以 while 开头的四行,并将它们替换为能够正确处理 window.

销毁的单行 tk.mainloop()

此外,如果您想保留原始代码,则没有理由同时调用 update_idletasksupdate。前者是后者的子集。

我同意其他人的意见,您应该在此处使用 mainloop(),但是如果您想保留原始代码,我会这样做,即跟踪布尔值并执行 while x == True反而。这样我们就可以将 x 的值更新为等于 False,这应该可以防止错误发生。

我们可以使用 protocol() 方法在应用程序关闭时更新我们的布尔值。

如果我们将此添加到您的代码中:

x = True

def update_x():
    global x
    x = False

tk.protocol("WM_DELETE_WINDOW", update_x)

并将您的 while 语句更改为:

while x == True:
    tk.update_idletasks()
    tk.update()
    time.sleep(0.01)

因此您的完整代码可能如下所示:

from tkinter import *
import random
import time


tk=Tk()
tk.title("My 21st Century Pong Game")
tk.resizable(0,0)
tk.wm_attributes("-topmost",1)

x = True

def update_x():
    global x
    x = False

tk.protocol("WM_DELETE_WINDOW", update_x)
canvas=Canvas(tk,bg="white",width=500,height=400,bd=0,highlightthickness=0)
canvas.pack()
tk.update()

class Ball:
    def __init__(self,canvas,color):
        self.canvas=canvas
        self.id=canvas.create_oval(30,30,50,50,fill=color)
        """ Note: x and y coordinates for top left corner and x and y coordinates for the bottom right corner, and finally the fill colour for the oval
        """
        self.canvas.move(self.id,0,0)

    def draw(self):
        pass 

ball1=Ball(canvas,'green')

while x == True:
    tk.update_idletasks()
    tk.update()
    time.sleep(0.01)

这将解决您的问题。

重申其他人所说的,您真正需要的是此处的 mainloop() 而不是您的 while i: 声明。

mainloop() 方法用于重置 Tk() 实例的循环一旦代码到达显示 tk.mainloop() 的行,它将成为下一个循环你的代码。

编写代码的正确方法是只使用 mainloop(),因为它会为 tkinter 实例执行所有更新。

使用 mainloop() 查看下面的代码:

from tkinter import *

tk=Tk()
tk.title("My 21st Century Pong Game")
tk.resizable(0,0)
tk.wm_attributes("-topmost",1)

canvas=Canvas(tk,bg="white",width=500,height=400,bd=0,highlightthickness=0)
canvas.pack()
tk.update()

class Ball:
    def __init__(self,canvas,color):
        self.canvas=canvas
        self.id=canvas.create_oval(30,30,50,50,fill=color)
        """ Note: x and y coordinates for top left corner and x and y coordinates for the bottom right corner, and finally the fill colour for the oval
        """
        self.canvas.move(self.id,0,0)

    def draw(self):
        pass 

ball1=Ball(canvas,'green')

tk.mainloop()