关闭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
为什么会引起这些例外?
答案 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)