Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

_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?

like image 309
narzero Avatar asked Apr 17 '13 12:04

narzero


1 Answers

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)

like image 75
Bryan Oakley Avatar answered Nov 15 '22 16:11

Bryan Oakley