开始导航

作为Python小白的你,初学tkinter时,有没有遇到过一些难的问题?
例如:图片格式不支持不显示图片,等等。
本文章将教大家解决,代码尽量简洁。
(之前有写过一篇,也有好多博主都写过了,本来不想再写,但之前的内容太糟,于是决定重写一篇,希望大家会好理解一些。)
写得不好,大神请不要嘲笑,谢谢。

1. tkinter.PhotoImage()不支持jpg等图片格式

由于tkinter.PhotoImage()仅支持GIFPGM/PPM文件格式,在使用jpg等其他格式的图片时,会报“_tkinter.TclError: couldn’t recognize data in image file “img.jpg””的错误:

  • 报错代码:
import tkinter

root = tkinter.Tk()

# 如下会报错:couldn't recognize data in image file "img.jpg"
# 报错翻译:无法识别图像文件“img.jpg”中的数据
photo = tkinter.PhotoImage(file="img.jpg")
tkinter.Label(master=root,image=photo).grid(row=0, column=0)

root.mainloop()

  • 解决办法如下:
    1.使用PIL包的ImageImageTk模块实现多种格式图片的载入,支持30多种格式。
    2.抛弃tkinter.PhotoImage(),改用ImageTk.PhotoImage()
    注意!!!都是PhotoImage(),别理解混了。 代码如下:
import tkinter
from PIL import Image, ImageTk

root = tkinter.Tk()

img = Image.open("img.jpg")  # 打开图片
photo = ImageTk.PhotoImage(img)  # 使用ImageTk的PhotoImage方法
tkinter.Label(master=root,image=photo).grid(row=0, column=0)

root.mainloop()

OK啦!(但只适合用在代码量少且简单的情况下,更好的方法请看第3个问题。)

2. 将ImageTk.PhotoImage()放在函数里图片不显示

不显示图片的代码如下:

from tkinter import Tk, Label
from PIL import Image, ImageTk

root = Tk()


def load_img():
    # 打开图片。
    # resize():无关紧要,示例图片太大,这里缩小一些。
    img = Image.open('img.jpg').resize((200, 200))

    photo = ImageTk.PhotoImage(img)  # 将该方法放在函数中,图片不显示

    # 图片用Label来显示
    Label(master=root, image=photo).grid(row=0, column=0)


load_img()  # 执行函数

root.mainloop()

运行后,图片并没有显示,究竟是怎么回事?

  • 原因:在调用load_img()函数后,垃圾回收机制会把变量photo给回收了。
  • 解决办法:使用global全局变量。如下(为了做对比,代码用图片展示):
    使用全局变量
    只需要在声明photo变量之前将它设为全局变量即可。
    注意global不要放在函数外面,否则会没效果。

3. 循环加入多张图片却只显示一张

栗子太多,只举其一叭~

from tkinter import Tk, Label
from PIL import Image, ImageTk

root = Tk()
# 总共4张图片
img_list = ["img.jpg", "img.png", "img.gif", "img.webp"]


def load_img(index, item):
    # 打开图片。
    # resize():示例图片太大,这里缩小一些。
    img = Image.open(item).resize((200, 200))

    # 设全局
    global photo
    photo = ImageTk.PhotoImage(img)

    # 图片用Label来显示
    Label(master=root, image=photo).grid(row=0, column=index)


# 使用for循环添加图片。enumerate:获取元素与其索引值,没啥意义,只是为了grid()显示
for index, item in enumerate(img_list):
    load_img(index, item)  # 执行函数

root.mainloop()

显示结果:
循环添加图片却只显示最后一张
啊!!为什么只有一张?
前面说过,垃圾回收机制会自动回收,可是,这里(第15行)明明添加了global,它却显示了最后一张,怎么办?
呵呵,阿娇:冇有使惊。解决办法这不就来了嘛!
解决办法:给他一个引用!至于什么引用,请看以下代码(注意第15、16、20行):

from tkinter import Tk, Label
from PIL import Image, ImageTk

root = Tk()
# 总共4张图片
img_list = ["img.jpg", "img.png", "img.gif", "img.webp"]


def load_img(index, item):
    # 打开图片。
    # resize():示例图片太大,这里缩小一些。
    img = Image.open(item).resize((200, 200))

    # 引用:添加一个Label,用来存储图片。使用PanedWindow也行。
    panel = Label(master=root)
    panel.photo = ImageTk.PhotoImage(img)  # 将原本的变量photo改为panel.photo

    # 图片用Label来显示,参数master改不改为panel都行,这里就不改了。
    # 注意:参数image改为panel.photo
    Label(master=root, image=panel.photo).grid(row=0, column=index)


# 使用for循环添加图片,enumerate:获取元素与其索引值
for index, item in enumerate(img_list):
    load_img(index, item)  # 执行函数

root.mainloop()

显示结果:
完美显示全部图片

第15行的global被抛弃,变成了Label组件,为的就是给每个显示图片的Label一个引用,不至于像变量那样被回收。
同样,前面的第1、2个问题,只需要添加个引用就完美了。这样就大功告成啦。
妈妈再也不用担心内存被回收啦!奥利给!!

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐