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

キャンバスは、追加するアイテムが増えるほど遅くなることが知られています (ただし、通常、1000 のアイテムまたは 1000 の数十のアイテムを問題なく処理できます)。いくつかの問題があります。1つは、他の回答が指摘しているように、オブジェクトをどんどん作成し続けることです。既存のオブジェクトを再利用し、それらの座標と色を更新すると、速度が劇的に向上するはずです。

2 番目の問題は、無限ループとスリープ ( 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 に答える
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)]

そしてドローボックスで:

canvas.itemconfig(rectangles[y][x], fill=color)
于 2012-05-09T12:58:44.960 に答える