Python – Tkinterで作成した画面, GUIの動作が重くなっていく現象の解決法

Python

はじめに

Python – Tkinterで作成した画面の更新を続けていくと、徐々に動作が重くなっていく場合があります。今回はこの現象の原因と解決法の解説を行います。

具体例と原因

動作が重くなっていくGUIの具体例として以下のexample1.pyのようなものがあります。

from random import randrange
import tkinter as tk

def draw():
    ##ランダムに生成した色の四角形を幅30、高さ30で16x16マスになるようにキャンバスに作成
    for i in range(256):
        color = '#%02X%02X%02X' % (randrange(0,255,20),randrange(0,255,20),randrange(0,255,20))
        canvas.create_rectangle((i%16)*30,(i//16)*30,(i%16)*30+30,(i//16)*30+30,fill=color)

root = tk.Tk()

root.geometry('480x530')

##ドットを配置する幅480、高さ480のキャンバスをx=0、y=0に配置
canvas = tk.Canvas(root,width=480,height=480)
canvas.place(x=0,y=0)

##ボタンを押すとdrawを呼び出し再描画
btn = tk.Button(text="更新",command=draw)
btn.place(x=220,y=500)

draw()

root.mainloop()

このコードは480×530のウィンドウの中に、ランダム色の四角形で構成された16×16のマスとボタンを一つ作成し、ボタンを押すごとにマスの色が変化するというものです。

このコードを実行し、更新ボタンを連打していくとマスの色が切り替わるのにかかる時間が徐々に長くなっていくと思います。

この徐々に重くなっていくという現象は、生成した四角形を削除せずに、その上に新たに四角形を生成し続けることで管理するオブジェクトの数が増えていってしまっていることが原因で起きています。

解決法

原因の裏を返し、管理するオブジェクトの数が増えていかないようにすれば、この問題を解決することができるということになります。

オブジェクト数増加の解消方法が今回のコードの場合は2つあるので以下の解決法1,2で紹介していきます。

解決法1

1つ目の解決法は、生成してある四角形を削除してから新たに再生成し直すというものです。

from random import randrange
import tkinter as tk

def draw():
    ##キャンバスに生成されているオブジェクトを全て削除する
    canvas.delete('all')
       
    for i in range(256):
        color = '#%02X%02X%02X' % (randrange(0,255,20),randrange(0,255,20),randrange(0,255,20))
        canvas.create_rectangle((i%16)*30,(i//16)*30,(i%16)*30+30,(i//16)*30+30,fill=color)

root = tk.Tk()

root.geometry('480x530')

canvas = tk.Canvas(root,width=480,height=480)
canvas.place(x=0,y=0)

btn = tk.Button(text="更新",command=draw)
btn.place(x=220,y=500)

draw()

root.mainloop()

先ほどのexample1.pyからの変更点は6行目に追加した “canvas.delete(‘all’)” のみです。

Tkinterのdelete(tag)メソッドは、引数として指定したタグのオブジェクトを削除するというもので、引数としてallを与えてあげることで、全てのオブジェクトを削除することができます。

今回はこれを利用して、更新ボタンを押すたびにcanvas上に生成した四角形を削除することでオブジェクト数の増加を防いでいます。

解決法2

2つ目の解決法は、生成した四角形の色を塗り直すというものです。

from random import randrange
import tkinter as tk

def draw():
    ##四角形の生成時に、それぞれにタグ 1 ~ 256 を指定
    for i in range(256):
        color = '#%02X%02X%02X' % (randrange(0,255,20),randrange(0,255,20),randrange(0,255,20))
        canvas.create_rectangle((i%16)*30,(i//16)*30,(i%16)*30+30,(i//16)*30+30,fill=color,tags=str(i+1))

def recolor():
    for i in range(256):
        color = '#%02X%02X%02X' % (randrange(0,255,20),randrange(0,255,20),randrange(0,255,20))
        canvas.itemconfig(str(i+1),fill=color)

root = tk.Tk()

root.geometry('480x530')

canvas = tk.Canvas(root,width=480,height=480)
canvas.place(x=0,y=0)

##ボタンを押すとrecolorを呼び出し、四角形に色を塗り直す
btn = tk.Button(text="更新",command=recolor)
btn.place(x=220,y=500)

draw()

root.mainloop()

example1.pyからの変更点は

  1. 8行目: 四角形の生成時にそれぞれに1 ~ 256 のタグを指定
  2. 23行目: 更新ボタンを押した際に呼び出される関数をdrawからrecolorに変更
  3. 10 ~ 13 行目: 既にある四角形の色を塗り直す関数を追加

の3点です。

Tkinterのitemconfig(tag,option)メソッドは、引数で指定したタグのオブジェクトに対して、同じく指定したオプションの変更を行うというものです。

こちらの手法では、このオプション変更を利用して、四角形の色を “fill=color” で塗り直すことで、画面更新時のオブジェクト増加を防いでいます。

コメント

タイトルとURLをコピーしました