Python Forum

Full Version: tkinter issue
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi guys,

I'm having a problem creating multiple buttons in tkinter using a for loop. I just can't figure out how to make each button unique. First task is to fill a 9x9 grid with buttons, which is successfully acomplished by the command below.
def grid_fill():
    a=14
    b=15
    for j in range(9):
        for i in range(9):
            buttons = Button(main, text = 0, width = 7, height = 3)
            buttons.place(x = a, y = b)
            a+=76.7
        a = 14
        b+=76.7
But my goal is not only to place these buttons but also assign each one a different command. The code above just places 81 buttons which are all the same. Any suggestions?

Thank you very much for all of your help in advance. Big Grin
I don't know how much benefit there is in making buttons in a loop when they are bound to different functions. Unless the functions are all the same function with different arguments.
from tkinter import *

def grid_fill(frame):
    colors = ['red', 'green']
    k = 0
    for j in range(5):
        for i in range(5):
            k += 1
            color = colors[i % len(colors)]
            b = Button(frame, text = str(k), width = 3, height = 2, bg=color)
            b.configure(command=lambda x=k: print(x))
            b.grid(row=j, column=i)

grid_fill(Tk())
mainloop()
I'm doing three things here
1. Calculating the button label.
2. Looking up the button color.
3. Setting a callback with button specific arguments.
OH! loking at your code I can now see what I was doing wrong. I misunderstood the lambda command but I think I understand now.
Thank you very much!





(Dec-06-2020, 07:27 PM)deanhystad Wrote: [ -> ]I don't know how much benefit there is in making buttons in a loop when they are bound to different functions. Unless the functions are all the same function with different arguments.
from tkinter import *

def grid_fill(frame):
    colors = ['red', 'green']
    k = 0
    for j in range(5):
        for i in range(5):
            k += 1
            color = colors[i % len(colors)]
            b = Button(frame, text = str(k), width = 3, height = 2, bg=color)
            b.configure(command=lambda x=k: print(x))
            b.grid(row=j, column=i)

grid_fill(Tk())
mainloop()
I'm doing three things here
1. Calculating the button label.
2. Looking up the button color.
3. Setting a callback with button specific arguments.
Were you doing something like this?
def grid_fill(frame):
    colors = ['red', 'green']
    k = 0
    for j in range(5):
        for i in range(5):
            k += 1
            color = colors[i % len(colors)]
            b = Button(frame, text = str(k), width = 3, height = 2, bg=color)
            b.configure(command=lambda : print(k))
            b.grid(row=j, column=i)
And when you pushed any button the callback function used the last value assigned to k?

This is because all the functions are bound to "lambda : print(k)" where "k" is a variable defined in the "grid_fill()" name space. All the lambda's are using the same "k". This is an unusual function variable in that it is not deleted as soon as the function ends. Since it is referenced multiple times it is not reclaimed by the garbage collection.

In my code I declared a variable for the lambda and initialized the value. It is very much like I wrote this:
def print_number(number = 5):
    print(number)
Where "5" is the value of "k" for that particular iteration.
Well I'm trying to make a program that solves sudoku where you input numbers and press button 'solve' and then it fills the rest of the empty spots. I thought I would make it this way : 9x9 grid filled with buttons with text = 0, and whenever you press a button its text changes to one above so you can easily input numbers.