2013-04-17 25 views
5

Khi đóng chương trình python 3, tôi nhận được một ngoại lệ lạ trong bảng điều khiển._tkinter.TclError: tên lệnh không hợp lệ ".4302957584"

Các Python 3 mã:

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

Dưới đây là toàn bộ 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 

Tại sao có những trường hợp ngoại lệ gây ra?

+0

Bạn có nhận được mã này từ cuốn sách đó không? Đây là cách sai để làm hoạt hình trong Tkinter, và đang góp phần vào vấn đề. Bạn có thể muốn tìm kiếm trang web này để biết cách tạo hoạt ảnh trong Tkinter. –

+0

Vâng tôi đã làm. Cuốn sách hiển thị mã ví dụ và bạn chỉ cần nhập mã đó vào. – narzero

+0

thật đáng tiếc. Đó là một ví dụ tồi. : - \ –

Trả lời

3

Vòng lặp ứng dụng chính window.mainloop sẽ không bao giờ được thực hiện mà không cần nhấn nút stop. Đó là nguồn gốc của vấn đề của bạn. Vòng lặp hoạt ảnh viết lại:

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

Cuộc gọi đến 'update' hoàn toàn không cần thiết trong ví dụ này. –

3

Khi bạn thoát khỏi chương trình, cửa sổ sẽ bị hủy. Sự hủy diệt này xảy ra sau khi vòng lặp sự kiện thông báo rằng ứng dụng đã thoát. Cách bạn có mã của bạn được cấu trúc, điều này xảy ra khi bạn gọi self.update(). Ngay sau cuộc gọi đó và sau khi các tiện ích đã bị hủy, bạn đang gọi self.canvas.delete("ball"). Vì tiện ích đã bị hủy trong câu lệnh trước, bạn sẽ gặp lỗi.

Lý do lỗi rất khó hiểu là Tkinter chỉ là trình bao bọc xung quanh trình thông dịch tcl/tk. Các widget Tk được đặt tên với một dấu chấm theo sau là một số ký tự, và tên widget cũng là các lệnh tcl. Khi bạn gọi phương thức delete của canvas, Tkinter dịch tham chiếu canvas thành tên tk widget nội bộ/lệnh tcl. Bởi vì các widget đã bị phá hủy, tk không nhận ra rằng như là một lệnh được biết đến và ném một lỗi.

Giải pháp sẽ yêu cầu bạn làm lại logic hoạt ảnh của mình. Bạn không nên có vòng lặp hoạt hình của riêng bạn. Thay vào đó, bạn cần sử dụng vòng lặp Tkinter (mainloop()) làm vòng lặp hoạt ảnh của mình. Có một vài ví dụ trên trang web này để chỉ cho bạn cách thực hiện (ví dụ: https://stackoverflow.com/a/11505034/7432)

Các vấn đề liên quan