Python 渲染时间随时间增加
鉴于此代码Python 渲染时间随时间增加,python,python-3.x,tkinter,tkinter-canvas,Python,Python 3.x,Tkinter,Tkinter Canvas,鉴于此代码 import tkinter canvas = tkinter.Canvas() canvas.pack() i = 0 k = 1 while True: canvas.create_text(100, 0+i, text="Python 3.6!", fill="red") canvas.update() canvas.create_rectangle(0, 0, canvas["width"], canvas["height"], fill=can
import tkinter
canvas = tkinter.Canvas()
canvas.pack()
i = 0
k = 1
while True:
canvas.create_text(100, 0+i, text="Python 3.6!", fill="red")
canvas.update()
canvas.create_rectangle(0, 0, canvas["width"], canvas["height"], fill=canvas["background"])
canvas.after(3)
i = i + k
if i==-1 or i==265:
k = -k
我们可以看到,随着while循环的每一个循环,文本的移动都会减慢
现在,由于我们每秒多次重新渲染整个画布,难怪渲染速度很慢。然而,为什么它会随着时间的推移而变慢呢?这是因为大量的对象文本和矩形对象堆积在一起吗?这可以避免吗?在每次迭代中,您都会创建一个新的文本项和一个矩形以隐藏上一个文本项,而不是移动文本,因此画布会变得拥挤,程序会变慢 有几种方法可以避免这种情况: 1) 删除文本,而不是将其隐藏在矩形后面:
text = canvas.create_text(100, i, text="Python 3.6!", fill="red")
...
canvas.delete(text)
2) 使用coords
更改现有项目的坐标:
import tkinter
canvas = tkinter.Canvas()
canvas.pack()
i = 0
k = 1
text = canvas.create_text(100, i, text="Python 3.6!", fill="red")
while True:
canvas.coords(text, 100, i) # change coordinates of the text
canvas.update()
canvas.after(3)
i = i + k
if i==-1 or i==265:
k = -k
3) 使用移动移动现有项目:
import tkinter
canvas = tkinter.Canvas()
canvas.pack()
i = 0
k = 1
text = canvas.create_text(100, i, text="Python 3.6!", fill="red")
while True:
canvas.move(text, 0, k) # increment by k the y coordinate of the text
canvas.update()
canvas.after(3)
i = i + k
if i==-1 or i==265:
k = -k
最后,您还可以使用after
方法制作动画,而不是while循环。比如:
import tkinter
root = tkinter.Tk()
canvas = tkinter.Canvas(root)
canvas.pack()
def motion(i, k):
canvas.coords(text, 100, i)
i = i + k
if i==-1 or i==265:
k = -k
canvas.after(3, motion, i, k)
i = 0
k = 1
text = canvas.create_text(100, 0, text="Python 3.6!", fill="red")
motion(i, k)
root.mainloop()
不是移动文本,而是在每次迭代中创建一个新的文本项和一个矩形以隐藏上一个文本项,这样画布会变得拥挤,程序会变慢
有几种方法可以避免这种情况:
1) 删除文本,而不是将其隐藏在矩形后面:
text = canvas.create_text(100, i, text="Python 3.6!", fill="red")
...
canvas.delete(text)
2) 使用coords
更改现有项目的坐标:
import tkinter
canvas = tkinter.Canvas()
canvas.pack()
i = 0
k = 1
text = canvas.create_text(100, i, text="Python 3.6!", fill="red")
while True:
canvas.coords(text, 100, i) # change coordinates of the text
canvas.update()
canvas.after(3)
i = i + k
if i==-1 or i==265:
k = -k
3) 使用移动移动现有项目:
import tkinter
canvas = tkinter.Canvas()
canvas.pack()
i = 0
k = 1
text = canvas.create_text(100, i, text="Python 3.6!", fill="red")
while True:
canvas.move(text, 0, k) # increment by k the y coordinate of the text
canvas.update()
canvas.after(3)
i = i + k
if i==-1 or i==265:
k = -k
最后,您还可以使用after
方法制作动画,而不是while循环。比如:
import tkinter
root = tkinter.Tk()
canvas = tkinter.Canvas(root)
canvas.pack()
def motion(i, k):
canvas.coords(text, 100, i)
i = i + k
if i==-1 or i==265:
k = -k
canvas.after(3, motion, i, k)
i = 0
k = 1
text = canvas.create_text(100, 0, text="Python 3.6!", fill="red")
motion(i, k)
root.mainloop()
琐事
你的怀疑是对的。重绘/渲染时间增加是因为通过堆叠对象(它们不会在每次迭代中消失,而是保留在内存中)泄漏内存,以及因为tkinter
同时重绘所有对象。从这一点上说,我认为解决办法是明确的
答复
当然可以避免
有两种选择:
如果您只需要设置一个对象的动画,那么您只需同时移动一个(并重新绘制一个)对象即可
考虑这个例子:
import tkinter as tk
class App(tk.Tk):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.canvas = tk.Canvas()
self.canvas.pack()
self.canvas.create_rectangle(0, 0, self.canvas["width"], self.canvas["height"], fill=self.canvas["background"])
self.text = self.canvas.create_text(100, 1, text="Python 3.6!", fill="red")
self.step = 3
self.simulate_things()
def simulate_things(self):
if 0 <= self.canvas.coords(self.text)[1] + self.step <= self.canvas.winfo_height():
# no need to change direction - still inside canvas
pass
else:
# switch direction
self.step *= -1
# you can use coords method as alternative
self.canvas.move(self.text, 0, self.step)
# scheduling next move
self.after(41, self.simulate_things)
if __name__ == '__main__':
app = App()
app.mainloop()
import tkinter as tk
class App(tk.Tk):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.canvas = tk.Canvas()
self.canvas.pack()
self.canvas.create_rectangle(0, 0, self.canvas["width"], self.canvas["height"], fill=self.canvas["background"])
self.texts = {}
self.i = 1
self.step = 3
self.simulate_things()
def simulate_things(self):
if self.i in self.texts:
# hide previous object (if exists)
self.canvas.itemconfigure(self.texts[self.i], state='hidden')
if 0 <= self.i + self.step <= self.canvas.winfo_height():
# no need to change direction - still inside canvas
pass
else:
# switch direction
self.step *= -1
self.i += self.step
if self.i in self.texts:
# show hidden object for a step (if exists)
self.canvas.itemconfigure(self.texts[self.i], state='normal')
else:
# or create a new one
self.texts[self.i] = self.canvas.create_text(100, self.i, text="Python 3.6!", fill="red")
# scheduling next move
self.after(41, self.simulate_things)
if __name__ == '__main__':
app = App()
app.mainloop()
如您所见,管理性能的主要目标是减少重绘量(并将对象量保持在最小值)
链接
-
-
-
-
琐事
你的怀疑是对的。重绘/渲染时间增加是因为通过堆叠对象(它们不会在每次迭代中消失,而是保留在内存中)泄漏内存,以及因为tkinter
同时重绘所有对象。从这一点上说,我认为解决办法是明确的
答复
当然可以避免
有两种选择:
如果您只需要设置一个对象的动画,那么您只需同时移动一个(并重新绘制一个)对象即可
考虑这个例子:
import tkinter as tk
class App(tk.Tk):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.canvas = tk.Canvas()
self.canvas.pack()
self.canvas.create_rectangle(0, 0, self.canvas["width"], self.canvas["height"], fill=self.canvas["background"])
self.text = self.canvas.create_text(100, 1, text="Python 3.6!", fill="red")
self.step = 3
self.simulate_things()
def simulate_things(self):
if 0 <= self.canvas.coords(self.text)[1] + self.step <= self.canvas.winfo_height():
# no need to change direction - still inside canvas
pass
else:
# switch direction
self.step *= -1
# you can use coords method as alternative
self.canvas.move(self.text, 0, self.step)
# scheduling next move
self.after(41, self.simulate_things)
if __name__ == '__main__':
app = App()
app.mainloop()
import tkinter as tk
class App(tk.Tk):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.canvas = tk.Canvas()
self.canvas.pack()
self.canvas.create_rectangle(0, 0, self.canvas["width"], self.canvas["height"], fill=self.canvas["background"])
self.texts = {}
self.i = 1
self.step = 3
self.simulate_things()
def simulate_things(self):
if self.i in self.texts:
# hide previous object (if exists)
self.canvas.itemconfigure(self.texts[self.i], state='hidden')
if 0 <= self.i + self.step <= self.canvas.winfo_height():
# no need to change direction - still inside canvas
pass
else:
# switch direction
self.step *= -1
self.i += self.step
if self.i in self.texts:
# show hidden object for a step (if exists)
self.canvas.itemconfigure(self.texts[self.i], state='normal')
else:
# or create a new one
self.texts[self.i] = self.canvas.create_text(100, self.i, text="Python 3.6!", fill="red")
# scheduling next move
self.after(41, self.simulate_things)
if __name__ == '__main__':
app = App()
app.mainloop()
如您所见,管理性能的主要目标是减少重绘量(并将对象量保持在最小值)
链接
-
-
-
-
您是在一般情况下提问,还是在您的示例中提问?这有点不清楚,因为首先你要说的是,这是一个“不足为奇的”。在那之后,你会在下一句中感到困惑。长话短说:是的,由于越来越多的对象被重新绘制,它影响了性能。是的,这是可以避免的。我想问一下我的怀疑是否正确,在这个例子中如何避免这种情况?你是在一般情况下还是在你的例子中问?这有点不清楚,因为首先你要说的是,这是一个“不足为奇的”。在那之后,你会在下一句中感到困惑。长话短说:是的,由于越来越多的对象被重新绘制,它影响了性能。是的,这是可以避免的。我想问一下我的怀疑是否正确,在这个例子中如何避免这种情况。谢谢你的解释!谢谢你的解释!非常感谢。实际上,我想知道如何避免while
循环。你是一个真正的读心术者:谢谢!实际上,我想知道如何避免while
循环。你是一个真正的读心术者:D