以下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
答案 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)