python-3.xtkinterphotoimage

Can't reuse variable assigned with tkinter.PhotoImage


I'm trying to loop through a dictionary that contains the names of icons that I want to add to a tkinter Menu object. Here's a snippet of the code:

token_menu = Menu(menubar, tearoff=0)
menubar.add_cascade(label="Tokens",
                    underline=0,
                    menu=token_menu)
for coin in cbp_symbols.keys():
    imgvar = PhotoImage(file=f"icons/{cbp_symbols[coin]['icon']}")
    token_menu.add_command(label=f"{coin} ({cbp_symbols[coin]['name']})",
                           image=imgvar,
                           compound=LEFT,
                           command=quit)
win.config(menu=menubar)

The problem I'm running into is the reuse of the imgvar variable. For example, if I run the loop once, the icon gets added. If I remove the loop and add each menu items separately (and change the name of imgvar to something like imgvar1, imgvar2, etc.), the icons get added. However, every time I try this loop it always dies on the second assignment of imgvar. I've tried deleting it, setting to null - nothing I've done works.

Now, if I remove the image commands, the menu populates with the names of all 38 coins in my dictionary. I've verified that the loop is picking up the right icon name/location.


Solution

  • It is because you used same variable imgvar to hold the references of PhotoImage instances, so only the final image has variable reference to it. The other images will then be garbage collected.

    For your case, you can use a list to store the references of the images:

    imagelist = []
    for coin in cbp_symbols.keys():
        imgvar = PhotoImage(file=f"icons/{cbp_symbols[coin]['icon']}")
        token_menu.add_command(label=f"{coin} ({cbp_symbols[coin]['name']})",
                               image=imgvar,
                               compound=LEFT,
                               command=quit)
        imagelist.append(imgvar) # save the reference of image