2013-04-17 8 views
5

Podczas zamykania programu python 3, otrzymuję dziwny wyjątek w konsoli._tkinter.TclError: niepoprawna nazwa polecenia ".4302957584"

Python kod 3:

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

Oto pełna Traceback:

/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 

Dlaczego te wyjątki spowodowane?

+0

Czy otrzymałeś ten kod z tej książki? Jest to zły sposób na animację w Tkinter i przyczynia się do tego problemu. Możesz przeszukać tę stronę internetową, aby dowiedzieć się, jak animować w Tkinter. –

+0

Tak, zrobiłem. Książka pokazuje przykładowy kod i po prostu trzeba go wpisać. – narzero

+0

Szkoda. To zły przykład. : - \ –

Odpowiedz

3

Główna pętla aplikacji window.mainloop nigdy nie zostanie wykonana bez naciśnięcia przycisku stop. Jest źródłem twojego problemu. Przepisz pętlę animacji:

def __init__(self): 
    ... 
    self.sleepTime = 20 
    self.isStopped = False 
    self.window = window 
    self.window.after(self.sleepTime, self.animate) 
    window.mainloop() 
    ... 

def animate(self): 
    if not self.isStopped: 
     self.canvas.update() 
     self.canvas.delete("ball") 

     for ball in self.ballList: 
      self.redisplayBall(ball) 
     self.window.after(self.sleepTime, self.animate) 
+4

W tym przykładzie wywołanie polecenia 'update' jest zupełnie niepotrzebne. –

3

Po zamknięciu programu okna są niszczone. To zniszczenie następuje po stwierdzeniu, że aplikacja zakończyła działanie. Sposób, w jaki masz uporządkowany kod, dzieje się, gdy zadzwonisz pod numer self.update(). Natychmiast po tym połączeniu i po zniszczeniu widżetów dzwonisz pod numer self.canvas.delete("ball"). Ponieważ widżet został zniszczony w poprzednim komunikacie, pojawi się błąd.

Powód, dla którego błąd jest tak tajemniczy, polega na tym, że Tkinter jest po prostu otoką wokół interpretera tcl/tk. Widżety TK są nazywane kropkami, po których występują niektóre znaki, a nazwy widgetów są również komendami tcl. Po wywołaniu metody z kanonu, Tkinter tłumaczy odniesienie do płótna na wewnętrzną nazwę polecenia/tcl widgetu tk. Ponieważ widget został zniszczony, tk nie rozpoznaje go jako znanego polecenia i zgłasza błąd.

Rozwiązanie wymaga powtórzenia logiki animacji. Nie powinieneś mieć własnej pętli animacji. Zamiast tego należy użyć pętli zdarzeń Tkinter (mainloop()) jako pętli animacji. Na tej stronie jest kilka przykładów, które pokazują (na przykład: https://stackoverflow.com/a/11505034/7432)

Powiązane problemy