lrcgfのブログ

趣味としてプログラミングを始めたので、そのあたりの話を中心に書いていくつもりです。

tkinterで画像が表示できない?

tkinterで画像を表示するにはたとえば

import tkinter
root = Tk()
im = PhotoImage(file = 'image.gif')
canvas = Canvas(root, width = 500, height = 500, bg = 'white')
canvas.create_image(100, 100, image = im)
canvas.pack()
root.mainloop()

でいいらしい。
ところが、

canvas.create_image(100, 100, image = PhotoImage(file = 'image.gif'))

と直接引数でPhotoImageを呼んだり、

def get_image():
    x = PhotoImage(file = 'life_game_dead_cell.gif')
    return x

canvas.create_image(100, 100, image = get_image())

と関数を使ってオブジェクト生成して渡すと、ウィンドウには何も表示されない(ように見える)。
これはかなり悩んだが、tkinterbook
'The application must keep a reference to the image object.'
という一文を発見して、たぶん次のようなことなんだろうと推測した。
まずpythonにはガベージコレクションなる機能があるらしい。
これは、プログラム実行中のある時点でどの変数からも参照?されていない状態になったオブジェクトは、それ以降そのオブジェクトにアクセスするのが不可能になるのでプログラム実行上必要ないとみなされ、メモリ節約などのために自動的に廃棄されるというものらしい。(お気楽pythonを読んでいたおかげで思いあたった:garbage collection)
PhotoImage()はPhotoImageオブジェクトを生成するけど、それを適当なグローバル変数などに入れておかないと、すぐに消滅してしまうのだろう。このtkinterの仕様が不親切な設計だと思うのは理解が足りないからだろうか。
まあ実際はどうなのか分からないけど、ガベージコレクションが怪しいとは思う。

しっかし、こんなの初心者には絶対分からんでしょ。
しかも厄介なのは、

canvas.create_image(100, 100, image = PhotoImage(file = 'image.gif'))
print(canvas.find_all())

canvasのitemを調べてみたら、きちんとさっきcreate_imageで作ったitem(のid)が登録されているということ。存在してるのに見えないよーなんでだよーってかなり長く悩んでしまった。勢いあまってstuck overfllowのアカウントまで作ってしまった。次の機会から活用してみようかな。