【Python】tkinterで画像を一定時間ごとに自動切換え
目的
pythonでは簡単にGUIを作成できるライブラリとしてtkinterというものがあります。
GUIをリッチにしたい場合には画像を使う場合がありますが、同じ画像をずっと表示しているだけではなく、何かをトリガにして画像を切り替えるという仕掛けを用意したい場合もあると思います。
tkinterではもちろん画像などの表示も可能ですが、このような画像の切り替えができるのかということを試しましたのでメモしていきます。
使用ライブラリ
今回は主に以下の3つを使用することにしました。
- tkinter
python上でGUIを構築するためのライブラリで、今回のメインライブラリになります。
- PIL(pillow)
python上で画像を処理するためのライブラリです。今回は画像を一定時間毎に切り替えることを試すので、そもそも画像を読み込んで処理するために使います。
- threading
画像を自動切換えする仕掛けを作るために使用します。詳しくは後述します。
なお、Anaconda3の環境では、デフォルトですべてimportできる状態になってますので、新たにpip installする必要はありません。
Step1 : による画像表示
まずは、基本的なtkinterの使い方として、単に画像を表示させるための関数を用意します。
具体的には以下のようなコードで画像を表示させる関数(show_image)を作ることができます。
#必要ライブラリの読み込み
import sys
import tkinter
from PIL import Image, ImageTk
import time
#画像を表示させるための関数定義
def show_image():
  #tkinterのTKインスタンス用意
root = tkinter.Tk()
root.title('test')
root.geometry("400x300")
  #画像読み込み(yourimage.jpgは任意の画像へのパスにすること)
img = Image.open('yourimage.jpg')
img = ImageTk.PhotoImage(img)
  #Canvasの用意
canvas = tkinter.Canvas(bg = "black", width=400, height=300)
canvas.place(x=100, y=50)
item = canvas.create_image(30, 30, image=img, anchor=tkinter.NW)
  #表示
root.mainloop()
方針としては、tkinterのメソッドからcanvasを用意して、その上にjpgイメージを載せる形で実現します。コード中に出てくるImageTkはjpgを扱いたい場合に使用します。
Step2 : 画像の切り替え
今回行いたいことは、Step1で作成した関数で表示した画像を自動で切り替えたいということです。しかし、上記コード中のroot.mainloopに入るとtkinterのgui上のbuttonなどのオブジェクトからしか制御を受け付けてくれなくなってしまうようでした。
実現したいのは、手動でbuttonを押すのではなく一定時間後に自動で切り替えたい、ということで、少々力業ではありますが、threadingライブラリを使用し、スレッドを立てる形で工夫しました。具体的には以下のコードで実現できました。
import sys
import tkinter
from PIL import Image, ImageTk
import threading
import time
def show_image():
  #外から触れるようにグローバル変数で定義
global item, canvas
root = tkinter.Tk()
root.title('test')
root.geometry("400x300")
img = Image.open('your_image.jpg')
img = ImageTk.PhotoImage(img)
canvas = tkinter.Canvas(bg = "black", width=400, height=300)
canvas.place(x=100, y=50)
item = canvas.create_image(30, 30, image=img, anchor=tkinter.NW)
root.mainloop()
#スレッドを立ててtkinterの画像表示を開始する
thread1 = threading.Thread(target=show_image)
thread1.start()
#切り替えたい画像を定義
img2 = Image.open('your_image2.jpg')
img2 = ImageTk.PhotoImage(img2)
time.sleep(3) #3秒毎に切り替え
#itemを差し替え
canvas.itemconfig(item,image=img2)
time.sleep(3)
#itemをもとに戻す
img = Image.open('your_image.jpg')
img = ImageTk.PhotoImage(img)
canvas.itemconfig(item,image=img)
canvasをグローバル変数で定義した上でスレッドを実行して画像を表示しておき、3秒経過したらcanvas内のjpsイメージを置き換え、また3秒経過したらもとの画像へ置き換え直す、という方式になっています。
まとめ
スマートなやり方かどうかはさておき、canvasをグローバルで定義してスレッドで実行しておき、そとからitemconfigで差し替えることで、一応やりたいことはできました。