Python Forum

Full Version: Why does the image for the button not appear?
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi all,

The below code is a simple game I'm trying to make within Tkinter. The current issue is that when I press deposit, the menu opens and the button appears, but the picture within the button doesn't appear, it's just a blank button. The button still works but the picture to go inside doesn't show. Can anyone help?

from tkinter import *
from tkinter.ttk import *
from PIL import ImageTk, Image
from playsound import playsound
import pygame

pygame.init()

window = Tk()
window.title("Dice Gamble")
window.attributes("-fullscreen", True)                                                                  
window.resizable(False, False)


pygame.mixer.music.load("dice_gamble_home_music.mp3")
pygame.mixer.music.play()


image_open = Image.open("Z:\Finley\School\Sixth Form\School Images\CS\casinodice.gif") #change to where the picture is
image = ImageTk.PhotoImage(image_open)

bg = Label(image=image)
bg.image = image

bg.place(x=-50, y=-50)

def play():
    print ("PLAY")

def deposit():
    deposit_page = Toplevel()
    deposit_page.title("Deposit")
    deposit_page.attributes("-fullscreen", True)                                                                  
    deposit_page.resizable(False, False)

    deposit_exit_button_photo = PhotoImage(file = r"Z:\Finley\School\Sixth Form\School Images\CS\exit.png")
    deposit_exit_button = Button(deposit_page, text="", image = deposit_exit_button_photo, command = exit_menu)
    deposit_exit_button.place(x=500,y=550)

def exit_menu():
    window.destroy()

def settings():
    print ("SETTINGS")


dice_gamble_label_photo = PhotoImage(file = r"Z:\Finley\School\Sixth Form\School Images\CS\dicegamble.png")
dice_gamble_label = Label(window, text="", image = dice_gamble_label_photo)
dice_gamble_label.place(x=400, y=50)

play_button_photo = PhotoImage(file = r"Z:\Finley\School\Sixth Form\School Images\CS\1c1p.png")
play_button = Button(window, text ="", image = play_button_photo, command=play)
play_button.place(x=500,y=250)

deposit_button_photo = PhotoImage(file = r"Z:\Finley\School\Sixth Form\School Images\CS\deposit.png")
deposit_button = Button(window, text="", image = deposit_button_photo, command = deposit)
deposit_button.place(x=500,y=400)

exit_button_photo = PhotoImage(file = r"Z:\Finley\School\Sixth Form\School Images\CS\exit.png")
exit_button = Button(window, text="", image = exit_button_photo, command = exit_menu)
exit_button.place(x=500,y=550)

settings_button_photo = PhotoImage(file = r"Z:\Finley\School\Sixth Form\School Images\CS\settings.png")
settings_button = Button(window, text="", image = settings_button_photo, command = settings)
settings_button.place(x=790,y=550)


window.mainloop()
deposit_exit_button_photo is a function variable and the only thing referencing the image. When the function exits the variable no longer exists and the image reference count goes to 0. When an object's reference count is zero the object is reclaimed by garbage collection. In short, the garbage man has your image.
(Oct-21-2021, 04:08 PM)deanhystad Wrote: [ -> ]deposit_exit_button_photo is a function variable and the only thing referencing the image. When the function exits the variable no longer exists and the image reference count goes to 0. When an object's reference count is zero the object is reclaimed by garbage collection. In short, the garbage man has your image.

Thanks for the help. I added this where necessary:

global deposit_exit_button_photo
Now the problem is fixed and the output is as expected. Once again, thank you.
Using global is not a good way to fix it
If you don't want to use classes which is a better way of organising GUI code where you could keep a reference to the image as an attribute of the class instance, you could do the following.
deposit_exit_button_photo = PhotoImage(file = r"Z:\Finley\School\Sixth Form\School Images\CS\exit.png")
deposit_exit_button = Button(deposit_page, text="", image = deposit_exit_button_photo, command = exit_menu)
deposit_exit_button.image = deposit_exit_button_photo
To keep a reference to it on the button object.

Also see Namespace flooding with * imports
One problem with using a global variable is what to do if you need more than one image? If you modified your program so it could make multiple buttons would you save the images in a list or a dictionary?

I like the idea of adding the image as an attribute to the button that uses the image. I think this will keep the image around as long the button is referenced. I even like this idea if you are using classes. The only time I would use a class variable to keep track of a button image would be for something like a toggle button when the same widget might toggle between different images.