0

In my code, the second implementation correctly shows "some_img.png" as a button background but the first does not.

class QuizInterface:

def __init__(self):
    self.window = Tk()
    self.window.title("Quizzler")
    self.window.config(bg=THEME_COLOR, padx=20, pady=20)

    # Example 1: Works as expected
    true_image = PhotoImage(file="./images/true.png")
    self.true_button = Button(image=true_image)
    self.true_button.grid(row=2, column=0)
    
    # Example 2: Does not work as expected
    self.true_button = Button(image=PhotoImage(file="./images/true.png"))
    self.true_button.grid(row=2, column=0)

    self.window.mainloop()
    
    # QuizInterface object is created and called in my main.py with no error.

No error is thrown for the first example which is confusing. Additionally, I've noticed that I cannot define an object and then in the same line call .grid(..) on that object without a "function does not return anything" warning. It seems as though tkinter does not like:

  1. defining multiple objects in a single line
  2. pack()/grid()/place() 'ing, in the same line as object construction

Why?

Mustafa
  • 45
  • 6

1 Answers1

0

Tkinter images get garbage collected if there is not a reference to them. This is why your first example works and the second does not.

When you create a widget you get a reference to that widget. You can then call pack/ place/grid on that reference, but these functions themselves do not return anything, so assigning to them gives None. It's like how a = [1,2,3].append(4) gives None because append does not return anything but a = [1,2,3] and a.append(4) does work.

Henry
  • 3,472
  • 2
  • 12
  • 36
  • I still don't quite understand because my button doesn't appear to be None, in the first implementation. I can still pack it; I just don't see an image. – Mustafa Nov 21 '22 at 21:16
  • You need a reference to the `PhotoImage`. This is what gets garbage collected. In your first example you pass the `PhotoImage` straight to `Button`. Because a reference to it does not exist anywhere, it gets garbage collected. – Henry Nov 21 '22 at 21:18
  • Why is it if I set the PhotoImage to None, and pass it as the button bg, the result is different than the above case where I pass the button a non-existent reference to a PhotoImage Object? In the former, the button is tiny, in the latter, the button is the size of the garbage collected image. Is it garbage collecting after rendering the button? – Mustafa Nov 21 '22 at 21:28
  • I'm guessing (I don't actually know) that it knows the size of the image, but the image itself has been garbage collected – Henry Nov 21 '22 at 22:34
  • *"This is why your second example works and the first does not."* - It is the reverse, first one work but second one does not. – acw1668 Nov 21 '22 at 23:08
  • @acw1668 Thanks, I missed that – Henry Nov 21 '22 at 23:30