0

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.

ajgringo619
  • 131
  • 2
  • 8
  • Does this answer your question? [Trying to put images from a folder onto tkinter buttons. Only the last image is displayed](https://stackoverflow.com/questions/62696252/trying-to-put-images-from-a-folder-onto-tkinter-buttons-only-the-last-image-is) – acw1668 Nov 27 '20 at 05:21
  • I wish it did. When I run my loop as posted, I'm not getting any images or new menu entries - no errors reported, just nothing at all. I'll try to see the logic used in your link. – ajgringo619 Nov 27 '20 at 05:24
  • In the link it talks about assigning icons to different Button objects. I can't find any documentation on how to edit an individual Menu entry, other than to add a new one. – ajgringo619 Nov 27 '20 at 05:35
  • The main point of the solution is to save the references of the images. For your case, use a list to store the images. – acw1668 Nov 27 '20 at 05:39
  • Wow - that actually worked! Thanks a bunch! If you want to add an answer, I'll upvote it. – ajgringo619 Nov 27 '20 at 05:42
  • Do you really need `imgvar` variable? can you do direct assignment like this: `image = PhotoImage(...),`? – Yaroslav Stetsyk Nov 27 '20 at 05:45
  • I tried that and it didn't work. – ajgringo619 Nov 27 '20 at 05:46

1 Answers1

1

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
acw1668
  • 40,144
  • 5
  • 22
  • 34