今天开始玩python的tkinter,遇到了一些问题。 我创建了一个动画,它以给定的速度在屏幕上移动一个球。 (当它到达屏幕时,它会返回)
为什么我的球看起来很糟糕?它的形状不统一? (就像经常眨眼一样)
有更好的方法吗?
代码:
from tkinter import *
import time
WIDTH = 800
HEIGHT = 500
SIZE = 100
tk = Tk()
canvas = Canvas(tk, width=WIDTH, height=HEIGHT, bg="grey")
canvas.pack()
color = 'black'
class Ball:
def __init__(self):
self.shape = canvas.create_oval(0, 0, SIZE, SIZE, fill=color)
self.speedx = 3
self.speedy = 3
def update(self):
canvas.move(self.shape, self.speedx, self.speedy)
pos = canvas.coords(self.shape)
if pos[2] >= WIDTH or pos[0] <= 0:
self.speedx *= -1
if pos[3] >= HEIGHT or pos[1] <= 0:
self.speedy *= -1
ball = Ball()
while True:
ball.update()
tk.update()
time.sleep(0.01)
终止程序后的错误:
Traceback (most recent call last):
File "C:/..py", line 29, in <module>
ball.update()
File "C:/Users/talsh/...py", line 20, in update
canvas.move(self.shape, self.speedx, self.speedy)
File "C:\Users\...\tkinter\__init__.py", line 2585, in move
self.tk.call((self._w, 'move') + args)
_tkinter.TclError: invalid command name ".!canvas"
这正常吗?我做错了什么吗?
最佳答案
我认为问题出在sleep()
。方法 sleep()
和 wait()
不应在 tkinter 中使用,因为它们会暂停整个应用程序,而不仅仅是提供计时器。
更新: 将方法命名为与内置方法同名也不是一个好主意。
您有 self.update()
并且 update()
已经在 Canvas 的 namespace 中。将 self.update()
更改为其他内容,例如:self.ball_update()
更新: 看起来 tikinter 以 15 毫秒的速率刷新并尝试以比这更快的速度触发可能会导致问题。在以与原始代码相同的速度移动时,我能够阻止圆圈变形的最接近方法是将计时器更改为 30 毫秒,并将速度变量从 3 更改为 9。
始终确保在 tkinter 应用程序的末尾有 mainloop()
。 mainloop()
是确保 tkinter 正常运行所必需的,并且没有可能因为它丢失而导致的错误,所以在最后添加 tk.mainloop()
您应该改用 after()
。这可能应该使用函数/方法作为您的定时循环来完成。像这样:
def move_active(self):
if self.active == True:
self.ball_update()
tk.after(30, self.move_active)
tk.update()
用上述方法替换您的 while 循环,并将类属性 self.active = True
添加到您的 __init__
部分。让我知道这是否能消除您的口吃:
from tkinter import *
import time
WIDTH = 800
HEIGHT = 500
SIZE = 100
tk = Tk()
canvas = Canvas(tk, width=WIDTH, height=HEIGHT, bg="grey")
canvas.pack()
color = 'black'
class Ball:
def __init__(self):
self.shape = canvas.create_oval(0, 0, SIZE, SIZE, fill=color)
self.speedx = 9 # changed from 3 to 9
self.speedy = 9 # changed from 3 to 9
self.active = True
self.move_active()
def ball_update(self):
canvas.move(self.shape, self.speedx, self.speedy)
pos = canvas.coords(self.shape)
if pos[2] >= WIDTH or pos[0] <= 0:
self.speedx *= -1
if pos[3] >= HEIGHT or pos[1] <= 0:
self.speedy *= -1
def move_active(self):
if self.active == True:
self.ball_update()
tk.after(30, self.move_active) # changed from 10ms to 30ms
ball = Ball()
tk.mainloop() # there should always be a mainloop statement in tkinter apps.
这里有一些与刷新计时器相关的问答链接。
Why are .NET timers limited to 15 ms resolution?
Why does this shape in Tkinter update slowly?
综上所述,您可能希望使用能够以更快的刷新率运行的替代方案,例如 Pygame
更新:
这是圆圈在 Canvas 中移动时发生的情况的图像。正如您所看到的,圆圈的一部分明显被切断了。这似乎发生在更新设置得越快。更新速度越慢(大多在 15 毫秒以上)接缝以减少此问题:
关于python - tkinter - 形状不统一,动画看起来很糟糕,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46060570/