tkinter中原生的加载图片方式,并不支持主流图片格式,要想加载jpg、png之类的,比较好的解决方式是使用PIL的Image, ImageTk模块来导入。
简单测试,在画布上添加一个图片,运行以下代码没有任何问题。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
from tkinter import *
from PIL import Image, ImageTk
tk = Tk()
canvas = Canvas(tk, width=500, height=500)
img = Image.open("avatar.jpg")
myPic = ImageTk.PhotoImage(img)
canvas.create_image(0, 0, image=myPic, anchor="nw")
canvas.pack(fill=BOTH, expand=True)
tk.mainloop()
|
但是当我把加载图片相关的操作封装成一个函数时,再测试,图片已经不展示了,这操作令人费解。查了相关资料,说函数执行完毕后,内部的变量被回收释放了。需要将图片设置成全局变量,函数销毁后图片还在。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
from tkinter import *
from PIL import Image, ImageTk
def openimg():
img = Image.open("avatar.jpg")
myPic = ImageTk.PhotoImage(img)
return myPic
tk = Tk()
canvas = Canvas(tk, width=500, height=500)
canvas.create_image(0, 0, image=openimg(), anchor="nw")
canvas.pack(fill=BOTH, expand=True)
tk.mainloop()
|
解决思路:设置全局变量
按照资料上的说法设置成全局变量后,图片确实成功显示了。但是这样使用,在测试例子中还好,实际应用中用起来就很混乱,太不优雅了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
from tkinter import *
from PIL import Image, ImageTk
myPic = None
def openimg():
global myPic
img = Image.open("avatar.jpg")
myPic = ImageTk.PhotoImage(img)
return myPic
tk = Tk()
canvas = Canvas(tk, width=500, height=500)
canvas.create_image(0, 0, image=openimg(), anchor="nw")
canvas.pack(fill=BOTH, expand=True)
tk.mainloop()
|
最终方案
设置一个全局的字典用于存放图片,进行统一管理,再定义一个全局方法,需要用到图片的地方统一调用它,传入图片路径、大小后就直接获得图片资源。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
# common.py
"""
存放打开的图片
"""
img_obj_dic: Dict[str, PhotoImage] = {}
def load_image(path, width, height):
"""
加载图片
"""
global img_obj_dic
key = path + str(width) + str(height)
key = key.encode("utf-8")
key = md5(key).hexdigest()
if key in img_obj_dic.keys():
return img_obj_dic[key]
img = ImageTk.PhotoImage(image=Image.open(path).resize((width, height)))
img_obj_dic.update({key: img})
return img_obj_dic[key]
|
最终结果,图片正常展示。可以看到获取图片资源已经非常方便了。
1
2
3
4
5
6
7
8
9
10
11
|
from tkinter import *
from ui.common import load_image
tk = Tk()
canvas = Canvas(tk, width=500, height=500)
canvas.create_image(0, 0, image=load_image('avatar.jpg', 200, 200), anchor="nw")
canvas.pack(fill=BOTH, expand=True)
tk.mainloop()
|