渲染时间随时间增加

时间:2017-12-07 07:31:21

标签: 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=canvas["background"])
    canvas.after(3)
    i = i + k

    if i==-1 or i==265:
        k = -k

我们可以看到,在while循环的每个循环中,文本的移动速度变慢。

现在,由于我们每秒多次重新渲染整个画布,难怪它很慢。但是,为什么它会随着时间的推移而放慢?是因为大量的物体文字和矩形物体堆积在一起?这可以避免吗?

2 个答案:

答案 0 :(得分:3)

不是移动文本,而是在每次迭代时创建一个新文本项和一个矩形来隐藏前一个文本项,因此画布变得拥挤而程序变慢。

有几种方法可以避免这种情况:

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)使用move移动现有项目:

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 :(得分:1)

琐事

你的怀疑是正确的。重绘/渲染时间增加是因为您通过堆叠对象泄漏内存(它们在每次迭代时都没有消失,它们被保存在内存中)并且因为tkinter在同一时间重绘它们。从那时起,我认为解决方案很明确。

答案

当然可以避免。

有两个选项:

  1. 如果您只需要为一个对象设置动画 - 那么您可以简单地移动一个(并重绘一个)对象。
  2. 考虑这个例子:

    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()
    
    1. 如果对多个对象有任何想法 - 你可以将他们的state切换到hidden / disabled(这也是删除对象的最佳方式,因为我们减少了{{ 1}} / id管理到最低限度)。该选项会告诉item不重绘它们。 但是,您需要跟踪已创建的对象以防止内存泄漏!
    2. 考虑这个例子:

      tkinter

      正如您所看到的 - 管理性能的主要目标是减少重绘次数(并将对象数量保持在最低水平)。

      链接