2017-09-22 375 views
0

我有以下代碼工作正常,直到我在程序結束時添加了while循環,基本上試圖保持循環運行永遠(更新屏幕),直到窗口關閉。_tkinter.TclError:無法調用「更新」命令:應用程序已被破壞錯誤

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

在加入上面的代碼,以現有的代碼,程序運行,但在出口,與此錯誤出現:

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

我已經看到了類似的問題與此對於這個特定的問題沒有任何答案可以幫助我解決這個問題。

整個代碼如下:

問題/問題:是什麼原因造成這個錯誤,我該如何解決?

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之外,畫布將出現,然後在瞬間消失後消失。要阻止窗口關閉,我們需要一個動畫循環 - 因此while 1:.....否則,作爲用戶在下面評論,我們不需要while 1:因爲IDLE已經有了這個地方(它可以在IDLE中正常工作,而無需使用while 1:..等等)

+1

只是固定的代碼縮進 - 對不起 – MissComputing

+0

邊注:避免使用'睡眠()'和'的wait()'用Tkinter的。這些方法對tkinter來說效果不佳。改用'after()'。 –

回答

1

我同意其他人你應該在這裏使用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() 
+0

如果正確的解決方案是用一行代碼替換所有的代碼,則您的解決方案需要四行低效代碼並將其轉換爲九。 –

+0

@BryanOakley正如我在我的回答中所說的,最好的選擇是使用'mainloop()'我明確表示。我只是爲OP提供了一種功能性的方式來使用他們的原始代碼,以便他們可以看到他們做錯了什麼。 –

1

您正在有效地嘗試實現您自己的mainloop而不是使用它。

要了解mainloop,您可以閱讀關於它here。您可以將其視爲您添加的新代碼的語法抽象;您的while循環。當你已經存在的時候,你幾乎試圖通過創建自己的循環來「更新屏幕」來重新創建輪子!

退出程序時,可以使用sys.exit()來避免錯誤。

編輯:

替換下面的代碼:

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

有了這個:

tk.mainloop() 

你的錯誤是因爲,它說,你不能更新,如果它的窗口已被銷燬。 mainloop應該處理這個問題。

+1

SneakyTurtle - 這絕對沒有意義。您可以發佈我需要使用的代碼 - 理想情況下,我想上傳代碼! :-)你是什麼意思用tk.mainloop()替換「while」?請澄清 – MissComputing

+0

同意 - 這不會幫助 - 除非您可以澄清或張貼代碼/答案。當然可以退出並避免使用sys.exit(),但是在什麼情況下以及如何使用? – 2017-09-22 18:00:10

+0

@MissComputing @pythoncarrot,我編輯了我的主帖,試圖解釋'mainloop'是什麼。 – SneakyTurtle

1

當您退出應用程序時,下次打電話給update_idletasks窗口對象被銷燬。然後嘗試在不存在的窗口上撥打update

您需要刪除以while開頭的所有四行,並用適當處理窗口破壞的單行tk.mainloop()替換它們。另外,如果您想保留原始代碼,則沒有理由同時撥打update_idletasksupdate。前者是後者的一個子集。

相關問題