python - tkinter - 形状不统一,动画看起来很糟糕

标签 python tkinter

今天开始玩python的tkinter,遇到了一些问题。 我创建了一个动画,它以给定的速度在屏幕上移动一个球。 (当它到达屏幕时,它会返回)

  1. 为什么我的球看起来很糟糕?它的形状不统一? (就像经常眨眼一样)

  2. 有更好的方法吗?

代码:

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 毫秒以上)接缝以减少此问题:

enter image description here

关于python - tkinter - 形状不统一,动画看起来很糟糕,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46060570/

相关文章:

python - 无法抓取屏幕上不可见但属于 slider /轮播的一部分的数据

Python异步队列未显示任何异常

python : Dynamically saving unknown faces in face recognition not working

python - 如何更新 Tix.ComboBox 的文本?

python - 无关的 Matplotlib 图(tkinter 中的绘图)

python - 如何等待鼠标点击?

python - 类型错误 : cannot pickle 'sqlite3.Connection' object

python - 将字典列表与特定值匹配相结合

python - 确定在 Tkinter 中按下了哪个按钮?

python - 有关将参数传递给 tkinter 按钮命令的更多信息