Tkinter画布更新速度在程序过程中降低

时间:2012-05-09 12:05:15

标签: python performance tkinter

以下python程序创建一个Tkinter Canvas对象并在其上绘制随机矩阵。 它还测量进行10次后续更新所需的时间。正如你可能从中看到的那样 下面的输出,这个时间在这个过程中持续增长 该程序。这种行为的原因是什么,我该如何解决?

from Tkinter import Tk, Canvas
import time
import numpy as np

window = Tk()
nRows = 30
nCols = 30
CELL_SIZE = 10
canvas = Canvas(window, width=CELL_SIZE*nRows,
                height=CELL_SIZE*nCols)
canvas.pack()
def drawbox(m):
    for y in range(nRows):
        for x in range(nCols):
            if m[y][x]:
                color = '#00FF00'
            else:
                color = '#000000'
            canvas.create_rectangle(CELL_SIZE*x,
                                    CELL_SIZE*y,
                                    CELL_SIZE*x+CELL_SIZE,
                                    CELL_SIZE*y+CELL_SIZE,
                                    fill=color,
                                    outline="#000000", width=1)
count = 0
timeStart = time.time()
while(True):
    board = np.random.rand(nRows, nCols) > 0.5
    if count % 10 == 0:
        print '%.1f seconds'%(time.time() - timeStart)
        timeStart = time.time()
        count = 0
    count += 1
    drawbox(board)
    canvas.after(5)
    canvas.update()

这是输出

0.0 seconds
1.7 seconds
4.1 seconds
6.3 seconds
8.7 seconds

3 个答案:

答案 0 :(得分:2)

每次在程序中调用drawbox时,您都会创建一组新的矩形,然后将它们绘制在旧矩形的顶部。随着时间的推移,你正在绘制越来越多的矩形(即使它看起来不像它,因为新的矩形被绘制在旧的矩形之上)。另请注意,根据程序的编写方式,您的内存会流失。

解决此问题的方法是在第一次复飞时创建矩形,然后使用canvas.itemconfig(rectangle_id,fill=color)在后​​续传递中更新矩形。我已经在你的drawbox下面发了一个(丑陋的)修改来完成这个。

def drawbox(m,_rectangles={}):
    if(_rectangles):
        myrectangles=_rectangles
    else:
        myrectangles={}

    for y in range(nRows):
        for x in range(nCols):
            if m[y][x]:
                color = '#00FF00'
            else:
                color = '#000000'
            if(not _rectangles):
                cid=canvas.create_rectangle(CELL_SIZE*x,
                                            CELL_SIZE*y,
                                            CELL_SIZE*x+CELL_SIZE,
                                            CELL_SIZE*y+CELL_SIZE,
                                            fill=color,
                                            outline="#000000", width=1)
                myrectangles[(y,x)]=cid
            else:
                canvas.itemconfig(_rectangles[(y,x)],fill=color)

    if(not _rectangles):
      _rectangles.update(myrectangles)

答案 1 :(得分:2)

您可以在每次更新时创建新项目。画布显示您之前添加的所有矩形,因此变得越来越慢(每个更新创建900个矩形,30个之后您的场景中有27,000个对象......)

为避免这种情况,您可以创建一次矩形,然后只更新它们的颜色。

你可以在toplevel:

rectangles = [ [ canvas.create_rectangle (CELL_SIZE*x, CELL_SIZE*y,
                    CELL_SIZE*x+CELL_SIZE, CELL_SIZE*y+CELL_SIZE,
                    fill="#000000",outline="#000000", width=1) 
                 for x in range(nCols)] for y in range(nRows)]

并在drawbox中:

canvas.itemconfig(rectangles[y][x], fill=color)

答案 2 :(得分:2)

已知画布的速度越慢,您添加的项目越多(尽管它可以典型地处理1000或1000的1000而没有太多问题)。你有几个问题。正如其他答案所指出的那样,一个是你不断创造越来越多的对象。通过重复使用现有对象并更新其坐标和颜色,您应该看到速度的显着提高。

第二个问题是你的无限循环和你的睡眠(canvas.after(5))。有一种更好的方法来实现这种效果,而不会让GUI一次冻结5毫秒的烦人副作用。

您需要做的就是创建一个绘制或更新对象的函数,然后在队列上放置一个事件,在一段时间后再次调用自身。然后它将自动更新,而无需显式创建循环。

例如:

def redraw():
    board = np.random.rand(nRows, nCols) > 0.5
    drawbox(board)
    canvas.after(100, redraw)