0

I am trying to make this UI from a stimulus as part of an assessment for school. I tried to import the provided school logo and banner on the top frame of the page and put images on the canvas but have yet to achieve any results. When I run the code, the pictures won't load at all. The code that I was working with is as followed:

from tkinter import *
import random
import time
import sqlite3
from tkinter import simpledialog
from tkinter import messagebox
from tkcalendar import *
from tkinter import ttk
import math
from PIL import Image, ImageTk
import winsound

#-------------Frames setup--------------------------
class VendingApp(Tk):
    def __init__(self):
        Tk.__init__(self)
        self._frame = None
        self.switch_frame(Home)

    def switch_frame(self, frame_class):
        #Destroys current frame and replaces it with a new one.
        new_frame = frame_class(self)
        if self._frame is not None:
            self._frame.destroy()
        self._frame = new_frame
        self._frame.pack()

####-----------------------Home page---------------------------
class Home(Frame):    
    def __init__(self, master):
        Frame.__init__(self, master)

        topFrame = Frame(self,width = 1024, height = 100, bd = 2, bg = "black")
        topFrame.pack()

        canvas_for_logo = Canvas(topFrame, height=100, width=100, bg = 'green') ##logo image
        canvas_for_logo.grid(row=0, column=0, sticky='ne')
        
        img_logo = Image.open("pic/sitelogo.png")
        img_logo = img_logo.resize((40,40), Image.ANTIALIAS)
        logo = ImageTk.PhotoImage(img_logo)
                                         
        canvas_for_logo.create_image(0, 0, anchor=NW, image=logo)


        canvas_for_banner = Canvas(topFrame, bg='red', height=100, width=924) #banner image
        canvas_for_banner.grid(row=0, column=1, sticky='nw')

        img_banner = Image.open("pic/banner.jpg")
        img_banner = img_banner.resize((40,40), Image.ANTIALIAS)
        banner = ImageTk.PhotoImage(img_banner)
                                         
        canvas_for_banner.create_image(0, 0, anchor=NW, image=banner)


        
        
        MidFrame = Frame(self,width = 1024, height = 628, bd = 2)
        MidFrame.pack()
        MidFrame.grid_propagate(False)



        BottomFrame = Frame(self,width = 1024, height = 50, bd = 2, bg = "black")
        BottomFrame.pack()
        BottomFrame.grid_propagate(False)
        

if __name__ == "__main__":
    root = VendingApp()
    #Sets the size of the window
    root.geometry("1024x768")
    #Renames the TITLE of the window
    root.title("Vending machine")
    root.geometry("1024x768")
    root.resizable(False, False) 


    root.mainloop()

I decided to make a separate file to test if the image would load without class, and it did. Codes are as followed:

from tkinter import ttk
from tkinter import*
import time
from PIL import Image, ImageTk

root = Tk()

canvas_for_logo = Canvas(root, height=100, width=100)
canvas_for_logo.pack()

img = Image.open("pic/sitelogo.png")
img = img.resize((105,105), Image.ANTIALIAS)
logo = ImageTk.PhotoImage(img)
                                 
canvas_for_logo.create_image(0, 0, anchor=NW, image=logo)


canvas_for_banner = Canvas(root, bg='red', height=100, width=924) #banner image
canvas_for_banner.pack()

img_banner = Image.open("pic/banner.jpg")
img_banner = img_banner.resize((924,100), Image.ANTIALIAS)
banner = ImageTk.PhotoImage(img_banner)
                                 
canvas_for_banner.create_image(0, 0, anchor=NW, image=banner)

root.mainloop()

Can someone please tell me what I did wrong? All replies are much appreciated. Thank you.

Y0SHI0N
  • 23
  • 7

1 Answers1

1

This is a typical Tkinter bug. I don't want to go into details cause I don't fully understand why it happens either, but it has something to do with the garbage collector and the fact that it doesn't consider the objects you have created for storing those images like being in use, so it deletes them; or something like that.

Luckily, it has an easy solution: you can either create an internal list variable, let say, self._images that stores each image you are using, something like:

self._images = list()
(...)
self._images.append(logo)
(...)
self._images.append(banner)

Or, you could assign to each canvas instance an attribute image (or img, it doesn't really matters) that stores the image instance it is going to carry. In your code, it will look similar to:

canvas_for_logo.image = logo
(...)
canvas_for_banner.image = banner

This way, you can avoid the garbage collector deleting what it shouldn't, cause now it acknowledges that this instances are being in use.

Dharman
  • 30,962
  • 25
  • 85
  • 135