3

以下 python 程序创建一个 TkinterCanvas对象并在其上绘制随机矩阵。它还测量进行 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
4

3 回答 3

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)
于 2012-05-09T12:57:37.513 回答
2

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

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

你可以在顶层:

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)
于 2012-05-09T12:58:44.960 回答
2

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

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

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

例如:

def redraw():
    board = np.random.rand(nRows, nCols) > 0.5
    drawbox(board)
    canvas.after(100, redraw)
于 2012-05-09T13:16:18.930 回答