Tkinter使用PIL导入图片不展示解决方法
   2

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()
站长微信
请备注来意
二维码