Вопрос-Ответ

Why does Tkinter image not show up if created in a function?

Почему изображение Tkinter не отображается, если оно создано в функции?

Этот код работает:

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()
Переведено автоматически
Ответ 1

Переменная photo является локальной переменной, которая собирает мусор после создания экземпляра класса. Решение включает сохранение ссылки на фотографию, например:

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

Если вы выполните поиск в Google по запросу "изображение tkinter не отображается", первый результат будет таким:

Почему мои изображения Tkinter не отображаются?

Ответ 2
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()

Просто добавьте global в определение img, и это сработает


Ответ 3

Проблема в том, что Python автоматически удаляет ссылки на переменную с помощью процесса, известного как сборка мусора. Решение заключается в сохранении ссылки или создании новой ссылки.

Ниже приведены способы:


  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 вы можете либо создать глобальный список, как это сделал я, либо использовать list внутри класса. Сработает и то, и другое.

Несколько полезных ссылок:

Ответ 4

Как правило, всякий раз, когда вы создаете свое изображение в блоке кода с отступом, вам нужно сохранить ссылку на это изображение. Это из-за автоматической сборки мусора в python, и он собирает все с refcount равным 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)
2024-01-30 12:08 python image tkinter