Tkinter .after() 对按键的响应速度不够快
Tkinter .after() not responding to keypress fast enough
我正在尝试制作一个正在向前移动的球的动画。此外,如果用户按下向上或向下按钮,它应该分别移动。
try:
import tkinter as tk
except ImportError:
import Tkinter as tk
class Movement:
def __init__(self, _frame, _canvas):
self.frame = _frame
self.canvas = _canvas
self.x = 10
self.y = 150
self.count = 0
self.update()
self.frame.bind_all("<Up>", lambda event: self.move_up())
self.frame.bind_all("<Down>", lambda event: self.move_down())
pass
def move_up(self):
self.y -= 10
pass
def move_down(self):
self.y += 10
pass
def update(self):
canvas.delete("obj")
self.count += 10
x2 = self.x + 50
y2 = self.y + 50
self.canvas.create_oval(self.x + self.count, self.y, x2 + self.count, y2, fill="red", tag="obj")
root.after(1000, self.update)
pass
root = tk.Tk()
width = 400
height = 400
canvas = tk.Canvas(root, width=width, height=height)
frame = tk.Frame(root, width=width, height=height)
if __name__ == '__main__':
Movement(frame, canvas)
canvas.grid()
root.mainloop()
不过有一个问题。鉴于球每 1 秒移动一次,它对按键的响应速度不够快。因此,如果您单击上踢,屏幕会在一秒钟后更新。
我知道 Tkinter 中有一个 .move() 函数。但是,由于很多原因我不能使用它。
我主要关心的是屏幕更新的时间间隔。
据我了解,您希望能够使计时器保持一致向前移动,但也能够在计时器之外的任何时间点上下移动。
为了完成这个,我将计时器移到了它自己的函数中,并允许 up down 函数调用对象 destroy/create 函数。
我已更新您的代码以反映这一点。
看看这段代码,如果有帮助请告诉我。
try:
import tkinter as tk
except ImportError:
import Tkinter as tk
class Movement:
def __init__(self, _frame, _canvas):
self.frame = _frame
self.canvas = _canvas
self.x = 10
self.y = 150
self.count = 0
self.object_timer()
self.frame.bind_all("<Up>",lambda event: self.move_up())
self.frame.bind_all("<Down>",lambda event: self.move_down())
def move_up(self):
self.y -= 10
self.update()
def move_down(self):
self.y += 10
self.update()
def update(self):
canvas.delete("obj")
x2 = self.x + 50
y2 = self.y + 50
self.canvas.create_oval(self.x + self.count, self.y, x2 + self.count, y2, fill="red", tag="obj")
def object_timer(self):
self.update()
self.count += 10
root.after(1000, self.object_timer)
root = tk.Tk()
width = 400
height = 400
canvas = tk.Canvas(root, width=width, height=height)
frame = tk.Frame(root, width=width, height=height)
if __name__ == '__main__':
Movement(frame, canvas)
canvas.grid()
root.mainloop()
这只是数学。如果你想让球以相同的速度移动,同时对按键反应更快,你可以调用两倍的更新,并将球移动一半。
例如,不是每秒移动 10 个像素,而是每十分之一秒移动 1 个像素。最终结果仍然是每秒 10 个像素。动画会更流畅,对按键的反应也会更快。
顺便说一句,没有必要在每次迭代时都删除并重新创建椭圆。可以移动 canvas 上的项目。删除和重新创建最终会导致性能问题,这与 canvas 的内部实现方式有关。您创建的每个对象都会获得一个新的唯一 id,并且 canvas 在拥有大量 id 时会变慢。 canvas 不会重复使用 id。
我也建议不要使用 lambda
。除非您需要它,否则它会增加复杂性而不会增加任何价值。只需在 move_up
和 move_down
:
中添加一个额外的参数
self.frame.bind_all("<Up>",self.move_up)
self.frame.bind_all("<Down>", self.move_down)
...
def move_up(self, event=None):
...
def move_down(self, event=None):
...
我正在尝试制作一个正在向前移动的球的动画。此外,如果用户按下向上或向下按钮,它应该分别移动。
try:
import tkinter as tk
except ImportError:
import Tkinter as tk
class Movement:
def __init__(self, _frame, _canvas):
self.frame = _frame
self.canvas = _canvas
self.x = 10
self.y = 150
self.count = 0
self.update()
self.frame.bind_all("<Up>", lambda event: self.move_up())
self.frame.bind_all("<Down>", lambda event: self.move_down())
pass
def move_up(self):
self.y -= 10
pass
def move_down(self):
self.y += 10
pass
def update(self):
canvas.delete("obj")
self.count += 10
x2 = self.x + 50
y2 = self.y + 50
self.canvas.create_oval(self.x + self.count, self.y, x2 + self.count, y2, fill="red", tag="obj")
root.after(1000, self.update)
pass
root = tk.Tk()
width = 400
height = 400
canvas = tk.Canvas(root, width=width, height=height)
frame = tk.Frame(root, width=width, height=height)
if __name__ == '__main__':
Movement(frame, canvas)
canvas.grid()
root.mainloop()
不过有一个问题。鉴于球每 1 秒移动一次,它对按键的响应速度不够快。因此,如果您单击上踢,屏幕会在一秒钟后更新。
我知道 Tkinter 中有一个 .move() 函数。但是,由于很多原因我不能使用它。
我主要关心的是屏幕更新的时间间隔。
据我了解,您希望能够使计时器保持一致向前移动,但也能够在计时器之外的任何时间点上下移动。
为了完成这个,我将计时器移到了它自己的函数中,并允许 up down 函数调用对象 destroy/create 函数。
我已更新您的代码以反映这一点。
看看这段代码,如果有帮助请告诉我。
try:
import tkinter as tk
except ImportError:
import Tkinter as tk
class Movement:
def __init__(self, _frame, _canvas):
self.frame = _frame
self.canvas = _canvas
self.x = 10
self.y = 150
self.count = 0
self.object_timer()
self.frame.bind_all("<Up>",lambda event: self.move_up())
self.frame.bind_all("<Down>",lambda event: self.move_down())
def move_up(self):
self.y -= 10
self.update()
def move_down(self):
self.y += 10
self.update()
def update(self):
canvas.delete("obj")
x2 = self.x + 50
y2 = self.y + 50
self.canvas.create_oval(self.x + self.count, self.y, x2 + self.count, y2, fill="red", tag="obj")
def object_timer(self):
self.update()
self.count += 10
root.after(1000, self.object_timer)
root = tk.Tk()
width = 400
height = 400
canvas = tk.Canvas(root, width=width, height=height)
frame = tk.Frame(root, width=width, height=height)
if __name__ == '__main__':
Movement(frame, canvas)
canvas.grid()
root.mainloop()
这只是数学。如果你想让球以相同的速度移动,同时对按键反应更快,你可以调用两倍的更新,并将球移动一半。
例如,不是每秒移动 10 个像素,而是每十分之一秒移动 1 个像素。最终结果仍然是每秒 10 个像素。动画会更流畅,对按键的反应也会更快。
顺便说一句,没有必要在每次迭代时都删除并重新创建椭圆。可以移动 canvas 上的项目。删除和重新创建最终会导致性能问题,这与 canvas 的内部实现方式有关。您创建的每个对象都会获得一个新的唯一 id,并且 canvas 在拥有大量 id 时会变慢。 canvas 不会重复使用 id。
我也建议不要使用 lambda
。除非您需要它,否则它会增加复杂性而不会增加任何价值。只需在 move_up
和 move_down
:
self.frame.bind_all("<Up>",self.move_up)
self.frame.bind_all("<Down>", self.move_down)
...
def move_up(self, event=None):
...
def move_down(self, event=None):
...