I know this a common problem, but I can't seem to solve it myself. My images don't display on Tkinter. I did research, and it seems that the problem is garbage collection. I tried everything to stop it, but it seems that nothing works. Here's my full code :
import tkinter as tk
from tkinter import ttk
from lxml import etree
from os import walk
from PIL import Image, ImageTk
class Gui(tk.Tk):
def __init__(self):
super().__init__()
self.frames = {}
self.l_widgets = {}
self.images = [] # Unused, doesn't work (nor does a dictionary)
# self.arbre = etree.parse("characters.xml") #relative path
self.arbre = etree.parse("C:/Users/nolan/OneDrive/Bureau/Code/wovnot/characters.xml") # absolute path
self.roles = {}
for root in self.arbre.xpath('//wolvesville'):
for pool in root.xpath('pool'):
self.roles[str(pool.get("name"))] = {}
for role in pool.xpath("character"):
self.roles[str(pool.get("name"))][role.get("name")] = (
role.get("surname"),
role.get("surname2"),
"r" + role.get("random"))
self.command = {}
def add_frame(self, name, grid_args=None, frame="main"):
if grid_args is None:
grid_args = {}
if frame == "main":
self.frames[name] = ttk.Frame(self)
else:
self.frames[name] = ttk.Frame(self.frames[frame])
self.frames[name].grid(**grid_args)
def create_entry(self, name, config_args=None, grid_args=None, frame="main"):
if grid_args is None:
grid_args = {}
if config_args is None:
config_args = {}
if frame == "main":
self.l_widgets[name] = (ttk.Entry(self), tk.StringVar())
else:
self.l_widgets[name] = (ttk.Entry(self.frames[frame]), tk.StringVar())
self.l_widgets[name][0].config(textvariable=self.l_widgets[name][1], **config_args)
self.l_widgets[name][0].grid(**grid_args)
def create_notebook(self, name, config_args=None, grid_args=None, frame="main"):
if grid_args is None:
grid_args = {}
if config_args is None:
config_args = {}
if frame == "main":
self.l_widgets[name] = (ttk.Notebook(self, **config_args), 0)
else:
self.l_widgets[name] = (ttk.Notebook(self.frames[frame], **config_args), 0)
self.l_widgets[name][0].grid(**grid_args)
def add_image(self, name, filename, size=(None, None)):
"""Unused, doesn't work"""
image_temp = Image.open(filename)
if size != (None, None):
image_temp.thumbnail(size)
image = ImageTk.PhotoImage(image_temp)
self.images[name] = image
return image
def create_a_label_with_an_image(self, name, filename, size=(None, None), config_args=None, grid_args=None,
frame="main"):
global immortals
if grid_args is None:
grid_args = {}
if config_args is None:
config_args = {}
immortals[name] = ImagePersistent(filename, size).image
self.l_widgets[name] = (ttk.Label(self.frames[frame]), immortals[name])
self.l_widgets[name][0].config(**config_args)
self.l_widgets[name][0].image = immortals[name]
self.l_widgets[name][0].grid(**grid_args)
def add_to_notebook(self, name, name_frame, config_args=None, grid_args=None):
if grid_args is None:
grid_args = {}
if config_args is None:
config_args = {}
self.frames[name_frame] = ttk.Frame(self)
self.l_widgets[name][0].add(self.frames[name_frame], **config_args)
self.l_widgets[name][0].grid(**grid_args)
class ImagePersistent:
def __init__(self, path, size=(None, None)):
self.path = path
self.temp = Image.open(path)
if size != (None, None):
self.temp.thumbnail(size)
self.image = ImageTk.PhotoImage(self.temp)
# END################################################################################################################################################################"""
global immortals
immortals = {}
# also tried globals().update({"immortals":{}})
# and immortals.update({name: thing})
g = Gui()
# mypath = "icons/characters"
mypath = "C:/Users/nolan/OneDrive/Bureau/Code/wovnot/icons/characters"
filenames = next(walk(mypath), (None, None, []))[2] # [] if no file
if not filenames:
raise Warning("no icons found")
print(filenames)
g.create_notebook("roles", grid_args={"rowspan": 4, "column": 0})
for pool in g.roles.keys():
g.add_to_notebook("roles", str(pool), config_args={"text": str(pool)})
nbr_images = 0
for icon in filenames:
if icon[:-4] in g.roles[pool].keys():
g.create_a_label_with_an_image(icon[:-4], mypath + "/" + icon,
size=(50, 50),
grid_args={"row": nbr_images // 12,
"column": nbr_images % 12},
frame=str(pool))
nbr_images += 1
g.mainloop()
Here's solutions for garbage collecting that seems to work with others didn't solve the problem :
self.l_widgets[name][0].image = immortals[name]
,lineSo i don't know. It's still gridded, and when I didn't use a class it worked! I feel like I've tried everything. I can give links to the images (all RGBA pngs) if needed. I know they do exist, since nbr_images values goes to 57.
I forgot to put image as an attribute in the config part. This code works :
def create_a_label_with_an_image(self, name, filename,size=(None,None), config_args=None, grid_args=None, frame="main"):
global immortals
if grid_args is None:
grid_args = {}
if config_args is None:
config_args = {}
immortals[name] = ImagePersistent(filename, size).image
self.l_widgets[name] = (ttk.Label(self.frames[frame]), immortals[name])
self.l_widgets[name][0].config(**config_args, image=immortals[name])
self.l_widgets[name][0].image = immortals[name]
self.l_widgets[name][0].grid(**grid_args)
Thanks @acw1668 for telling me. I'll close the subject.