Search code examples
pythontkintertkinter-button

TKinter button won't work if inside function


I have this code

import tkinter as tk
from tkinter import ttk

class Window(tk.Tk):
    def __init__(self) -> None:
        super().__init__()
        
        self.mainloop()        

I want to add button with image to it

import tkinter as tk
from tkinter import ttk

class Window(tk.Tk):
    def __init__(self) -> None:
        super().__init__()
        img = tk.PhotoImage(file="close.png")
        button = ttk.Button(self, text="Click me!", image=img, compound="right")
        button.config(image=img)
        button.pack()
        self.mainloop()        

Properly working button

And that works as intended
But when i try to move this button inside a class method, it wont show any image

import tkinter as tk
from tkinter import ttk

class Window(tk.Tk):
    def __init__(self) -> None:
        super().__init__()
        self.closeButton()
        self.mainloop()  
    def closeButton(self):
        img = tk.PhotoImage(file="close.png") 
        button = ttk.Button(self, text="Click me!", image=img, compound="right")
        button.config(image=img)
        button.pack()

Improperly working button

I already tried changing the way i load images to using PIL, but nothing changed.
I also tried making another class just for button, but this works worse than when its in function.

Can someone explaing to me why its happening, and maybe suggest a solution?


Solution

  • Your PhotoImage object is created inside the closeButton method and is therefore garbage collected after the function has run. See the comment under this answer.

    Create your image object while initializing Window:

    class Window(tk.Tk):
        def __init__(self) -> None:
            super().__init__()
            self.close_img = tk.PhotoImage(file="close.png") 
            self.closeButton()
            self.mainloop()
        def closeButton(self):
            button = ttk.Button(self, text="Click me!", image=self.close_img, compound="right")
            button.pack()