_tkinter.TclError:命令名称无效“.4302957584”

时间:2013-04-17 12:09:25

标签: python user-interface tkinter

关闭python 3程序时,我在控制台中遇到一个奇怪的异常。

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

这是完整的追溯:

/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

为什么会引起这些例外?

2 个答案:

答案 0 :(得分:4)

如果不按window.mainloop按钮,将永远不会执行主应用程序循环stop。这是你的问题的根源。重写动画循环:

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)

答案 1 :(得分:4)

退出程序时,窗口将被销毁。在事件循环通知应用程序退出后发生此破坏。您编写代码的方式,当您致电self.update()时会发生这种情况。在该调用之后,以及在小部件被销毁之后,您正在呼叫self.canvas.delete("ball")。由于小部件在前一个语句中被销毁,因此会出现错误。

错误如此神秘的原因是Tkinter只是tcl / tk解释器的包装器。 Tk小部件以点跟随一些字符命名,小部件名称也是tcl命令。当您调用画布的delete方法时,Tkinter会将画布引用转换为内部tk小部件名称/ tcl命令。由于窗口小部件已被销毁,因此tk无法将其识别为已知命令并引发错误。

解决方案将要求您重做动画逻辑。你不应该拥有自己的动画循环。相反,您需要使用Tkinter eventloop(mainloop())作为动画循环。本网站上有一些示例向您展示如何(例如:https://stackoverflow.com/a/11505034/7432