tkinter - 形状不均匀,动画看起来很糟糕

The*_*hip 3 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)
Run Code Online (Sandbox Code Playgroud)

终止程序后的错误:

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"
Run Code Online (Sandbox Code Playgroud)

这是正常的吗?我做错了吗?

Mik*_*SMT 5

我想成像的问题来自于sleep().这些方法sleep()wait()不应该在Tkinter的使用,因为它们会暂停整个应用程序,而不是仅仅提供一个计时器.

更新:命名一个与内置方法同名的方法也不是一个好主意.

你已经self.update()并且update()已经在画布的名称空间中了.换成self.update()其他类似的东西:self.ball_update()

更新:看起来tikinter以15毫秒的速度刷新并试图以比这更快的速度发射可能导致问题.最接近我能够阻止圆圈扭曲,同时以与原始代码相同的速率移动,将计时器更改为30毫秒,并将速度变量从3更改为9.

始终确保你有mainloop()tkinter应用程序的结尾.mainloop()需要确保tkinter正常运行,没有可能因为它丢失而导致的错误,所以最后添加tk.mainloop()

你应该使用after().这可能应该使用函数/方法作为您的定时循环.像这样的东西:

def move_active(self):
    if self.active == True:
        self.ball_update()
        tk.after(30, self.move_active)
        tk.update()
Run Code Online (Sandbox Code Playgroud)

用上面的方法替换while循环,并将class属性添加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.
Run Code Online (Sandbox Code Playgroud)

以下是与刷新计时器相关的Q/A的一些链接.

为什么.NET计时器的分辨率限制在15毫秒?

为什么Tkinter中的这种形状会慢慢更新?

所有这一切,你可能想要使用一个可能能够以更快的重新刷新率运行的替代品,如Pygame

更新:

这是一个圆圈在画布中移动时发生的事情的图像.正如你所看到的那样,圆圈的药水明显被切断了.这似乎发生更新设置得越快.更新速度越慢(大多数超过15毫秒)以减少此问题:

在此输入图像描述

  • 使用`after`时,您不需要调用`update`.调用`after`之后,但在下次运行之前,`update`将自动发生. (2认同)