Home > Software engineering >  Creating multiple widget using for loop in tkinter
Creating multiple widget using for loop in tkinter

Time:04-04

I would like to create multiple button with each button in variable , for example btn_0,btn_1,....,btn_i this is so configure and change them letter. I have folder with images names q0.png,q1.png,..... each button takes an image

I am able to create and pack multiple buttons via (without images on button)

for i in range(5):
    tk.Button(second_frame,text=f'Button No. {i}').pack()

-- for single instance

j=0
path = f'Questions/q{j}.png'
btn_img_path = tk.PhotoImage(file=path)
tk.Button(
    second_frame,
    image=btn_img_path,
    borderwidth=0,
    highlightthickness=0,
    command=lambda:print('A'),
    relief="flat"

).pack()

but trying to do it in a for loop -- only last button appear with image, other buttons don't appear at all, but their place is empty (last image is packed down in window) it seems like they are created and then overwritten

for i in range(5):
    path_q = f'Questions/q{i}.png'
    btn_img = tk.PhotoImage(file=path_q)
    tk.Button(second_frame,
              image=btn_img,
              borderwidth=0,
              highlightthickness=0,
              command=lambda:print(i),
              relief="flat").pack()

CodePudding user response:

Here is piece of code you could add that I guess would meet your expectations:

for i in range(5):
    path_q = f'Questions/q{i}.png'
    btn_img = tk.PhotoImage(file=path_q)
    btn_name = f'btn_{i}'
    btn_name = tk.Button(second_frame,
    image=btn_img,
    borderwidth=0,
    highlightthickness=0,
    command=lambda:print(i),
    relief="flat").pack()

pls tell me if this causes any problems as I cannot test the code if it works or not, by commenting. I guess the indenting is wrong but that is fixable

CodePudding user response:

There are two issues in the code:

  • using same variable btn_img for all the images, so only the last image is being referenced and the rest are garbage collected. You need to keep references to all the images to avoid garbage collection.

  • command=lambda:print(i) will make all buttons to print the same value (it is 4 in your case) when the buttons are clicked. You need to use default value of argument to fix it: command=lambda i=i:print(i).

Below is the updated for loop:

for i in range(5):
    path_q = f'Questions/q{i}.png'
    btn_img = tk.PhotoImage(file=path_q)
    btn = tk.Button(second_frame,
                    image=btn_img,
                    borderwidth=0,
                    highlightthickness=0,
                    command=lambda i=i:print(i),  # used default value of argument
                    relief="flat")
    btn.pack()
    btn.image = btn_img  # save reference of image

If you want to access the buttons later, it is better to use a list to store the references of the buttons.

  • Related