Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
523 views
in Technique[技术] by (71.8m points)

python - _tkinter.TclError: invalid command name ".4302957584"

When closing the python 3 program, I get a strange exception in the console.

The Python 3 code:

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

Here's the full 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

Why are these exceptions caused?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

When you exit the program, the windows are destroyed. This destruction happens after the event loop notices the application has exited. The way you have your code structured, this happens when you call self.update(). Immediately after that call, and after the widgets have been destroyed, you are calling self.canvas.delete("ball"). Since the widget was destroyed in the previous statement, you get the error.

The reason the error is so cryptic is that Tkinter is just a wrapper around a tcl/tk interpreter. Tk widgets are named with a dot followed by some characters, and widget names are also tcl commands. When you call the delete method of the canvas, Tkinter translates the canvas reference to the internal tk widget name / tcl command. Because the widget has been destroyed, tk doesn't recognize that as a known command and throws an error.

The solution is going to require you to redo your animation logic. You should not have your own animation loop. Instead, you need to use the Tkinter eventloop (mainloop()) as your animation loop. There are a few examples on this site to show you how (for example: https://stackoverflow.com/a/11505034/7432)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...