2013-04-17 12 views
5

Quando si chiude il programma python 3, ottengo una strana eccezione nella console._tkinter.TclError: nome comando non valido ".4302957584"

Il Python 3 Codice:

from tkinter import * 
from random import randint 

# Return a random color string in the form of #RRGGBB 
def getRandomColor(): 
    color = "#" 
    for j in range(6): 
     color += toHexChar(randint(0, 15)) # Add a random digit 
    return color 

# Convert an integer to a single hex digit in a character 
def toHexChar(hexValue): 
    if 0 <= hexValue <= 9: 
     return chr(hexValue + ord('0')) 
    else: # 10 <= hexValue <= 15 
     return chr(hexValue - 10 + ord('A')) 

# Define a Ball class 
class Ball: 
    def __init__(self): 
     self.x = 0 # Starting center position 
     self.y = 0 
     self.dx = 2 # Move right by default 
     self.dy = 2 # Move down by default 
     self.radius = 3 
     self.color = getRandomColor() 

class BounceBalls: 
    def __init__(self): 
     self.ballList = [] # Create a list for balls 

     window = Tk() 
     window.title("Bouncing Balls") 

     ### Create Canvas ### 
     self.width = 350 
     self.height = 150 
     self.canvas = Canvas(window, bg = "white", width = self.width, height = self.height) 
     self.canvas.pack() 


     ### Create Buttons ### 
     frame = Frame(window) 
     frame.pack() 

     btStop = Button(frame, text = "Stop", command = self.stop) 
     btStop.pack(side = LEFT) 

     btResume = Button(frame, text = "Resume", command = self.resume) 
     btResume.pack(side = LEFT) 

     btAdd = Button(frame, text = "Add", command = self.add) 
     btAdd.pack(side = LEFT) 

     btRemove = Button(frame, text = "Remove", command = self.remove) 
     btRemove.pack(side = LEFT) 

     self.sleepTime = 20 
     self.isStopped = False 
     self.animate() 

     window.mainloop() 

    def stop(self): # Stop animation 
     self.isStopped = True 

    def resume(self): 
     self.isStopped = False 
     self.animate() 

    def add(self): # Add a new ball 
     self.ballList.append(Ball()) 

    def remove(self): 
     self.ballList.pop() 

    def animate(self): 
     while not self.isStopped: 
      self.canvas.after(self.sleepTime) 
      self.canvas.update() 
      self.canvas.delete("ball") 

      for ball in self.ballList: 
       self.redisplayBall(ball) 

    def redisplayBall(self, ball): 
     if ball.x > self.width or ball.x < 0: 
      ball.dx = -ball.dx 

     if ball.y > self.height or ball.y < 0: 
      ball.dy = -ball.dy 

     ball.x += ball.dx 
     ball.y += ball.dy 
     self.canvas.create_oval(ball.x - ball.radius, ball.y - ball.radius, \ 
           ball.x + ball.radius, ball.y + ball.radius, \ 
           fill = ball.color, tags = "ball") 

BounceBalls() 

Ecco il Traceback completo:

/Library/Frameworks/Python.framework/Versions/3.3/bin/python3 "/Users/narek_a/Dropbox/Python/PycharmProjects/Introduction to Programming/Chapter 10.py" 
Traceback (most recent call last): 
    File "/Users/narek_a/Dropbox/Python/PycharmProjects/Introduction to Programming/Chapter 10.py", line 446, in <module> 
    BounceBalls() 
    File "/Users/narek_a/Dropbox/Python/PycharmProjects/Introduction to Programming/Chapter 10.py", line 407, in __init__ 
    self.animate() 
    File "/Users/narek_a/Dropbox/Python/PycharmProjects/Introduction to Programming/Chapter 10.py", line 428, in animate 
    self.canvas.delete("ball") 
    File "/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/tkinter/__init__.py", line 2344, in delete 
    self.tk.call((self._w, 'delete') + args) 
_tkinter.TclError: invalid command name ".4302957584" 

Process finished with exit code 1 

Perché queste eccezioni causate?

+0

Hai ricevuto questo codice da quel libro? Questo è il modo sbagliato di fare animazione in Tkinter e contribuisce al problema. Potresti voler cercare su questo sito web come animare in Tkinter. –

+0

Sì, l'ho fatto. Il libro mostra il codice di esempio e devi solo scriverlo. – narzero

+0

è un peccato. È un cattivo esempio. : - \ –

risposta

3

L'anello di applicazione principale window.mainloop non verrà mai eseguito senza premere il pulsante stop. È la fonte del tuo problema. Riscrivi il ciclo dell'animazione:

+4

In questo esempio la chiamata a 'update' non è necessaria. –

3

Quando si esce dal programma, le finestre vengono distrutte. Questa distruzione si verifica dopo che il ciclo degli eventi rileva che l'applicazione è stata chiusa. Il modo in cui è strutturato il codice, questo succede quando chiami self.update(). Subito dopo la chiamata e dopo che i widget sono stati distrutti, chiami self.canvas.delete("ball"). Poiché il widget è stato distrutto nell'istruzione precedente, si ottiene l'errore.

Il motivo per cui l'errore è così criptico è che Tkinter è solo un wrapper attorno a un interprete tcl/tk. I widget Tk sono nominati con un punto seguito da alcuni caratteri, ei nomi dei widget sono anche comandi tcl. Quando si chiama il metodo delete dell'area di disegno, Tkinter converte il riferimento del canvas al nome del widget tk interno/comando tcl. Poiché il widget è stato distrutto, tk non lo riconosce come comando noto e genera un errore.

La soluzione richiederà la ripetizione della logica di animazione. Non dovresti avere il tuo ciclo di animazione. Invece, è necessario utilizzare il eventloop Tkinter (mainloop()) come loop dell'animazione. Ci sono alcuni esempi su questo sito per mostrarti come (ad esempio: https://stackoverflow.com/a/11505034/7432)

Problemi correlati