如果在函数中创建,为什么 Tkinter 图像不显示?

问题描述 投票:0回答:5

此代码有效:

import tkinter

root = tkinter.Tk()
canvas = tkinter.Canvas(root)
canvas.grid(row = 0, column = 0)
photo = tkinter.PhotoImage(file = './test.gif')
canvas.create_image(0, 0, image=photo)
root.mainloop()

它给我看图像。

现在,这段代码可以编译但没有显示图像,我不知道为什么,因为它是相同的代码,在一个类中:

import tkinter

class Test:
    def __init__(self, master):
        canvas = tkinter.Canvas(master)
        canvas.grid(row = 0, column = 0)
        photo = tkinter.PhotoImage(file = './test.gif')
        canvas.create_image(0, 0, image=photo)

root = tkinter.Tk()
test = Test(root)
root.mainloop()
python image tkinter tkinter-canvas
5个回答
115
投票

变量

photo
是一个局部变量,它在类实例化后被垃圾收集。保存对照片的引用,例如:

self.photo = tkinter.PhotoImage(...)

如果你在谷歌上搜索“tkinter image doesn't display”,第一个结果是这样的:

为什么我的 Tkinter 图片没有出现?(FAQ 答案目前not 过时)


7
投票
from tkinter import *
from PIL import ImageTk, Image

root = Tk()

def open_img():
    global img
    path = r"C:\.....\\"
    img = ImageTk.PhotoImage(Image.open(path))
    panel = Label(root, image=img)
    panel.pack(side="bottom", fill="both")
but1 = Button(root, text="click to get the image", command=open_img)
but1.pack()
root.mainloop() 

只要在 img 定义中添加 global 就可以了


7
投票

问题是 Python 通过称为 Garbage Collection 的过程自动删除对变量的引用。解决方案是保存参考或创建新参考。

以下是方法:

  1. 使用
    self
    增加引用计数并保存引用。
import tkinter

class Test:
    def __init__(self, master):
        canvas = tkinter.Canvas(master)
        canvas.grid(row = 0, column = 0)
        self.photo = tkinter.PhotoImage(file = './test.gif') # Changes here
        canvas.create_image(0, 0, image=self.photo) # Changes here

root = tkinter.Tk()
test = Test(root)
root.mainloop()
  1. 将其保存到列表中以增加引用计数并保存引用。
import tkinter
l=[]
class Test:

    def __init__(self, master):
        canvas = tkinter.Canvas(master)
        canvas.grid(row = 0, column = 0)
        photo = tkinter.PhotoImage(file = './test.gif')
        l.append(photo)
        canvas.create_image(0, 0, image=photo)

root = tkinter.Tk()
test = Test(root)
root.mainloop()

在使用方法 2 时,您可以像我一样创建一个全局列表,也可以在类中使用列表。两者都可以。

一些有用的链接:


2
投票

根据经验,每当您在缩进代码块中创建图像时,您需要保护对该图像的引用。这是因为 python 的自动垃圾收集,当它销毁/离开那个框架/页面/缩进代码块时,它会收集引用计数为 0 的所有内容。


处理它的规范方法在全局命名空间中的某处有一个图像列表并将您的图像引用添加到该列表。这很方便但效率不高,应该用于小型应用程序。

import tkinter as tk

global_image_list = []
global_image_list.append(tk.PhotoImage(file = 'test.png'))

一个更有效的方法将一个属性绑定到您的小部件或类,它为您保留该参考,正如布莱恩在他的回答中所建议的那样。如果您执行

self.image
widget.image
之前分配的
widget = tk.Widget(..
,这没有什么区别。但是,如果您想进一步使用该图像,即使小部件被销毁并被垃圾收集,这也可能不是正确的方法。

import tkinter as tk

root = tk.Tk()
label = tk.Label(root, text='test')
label.image = tk.PhotoImage(file = 'test.png')
label.configure(image=label.image)

0
投票

只需添加

global photo
作为函数内的第一行。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.