Change your lambda to lambda i=i: self.open_this(i).
This may look magical, but here's what's happening. When you use that lambda to define your function, the open_this call doesn't get the value of the variable i at the time you define the function. Instead, it makes a closure, which is sort of like a note to itself saying "I should look for what the value of the variable i is at the time that I am called". Of course, the function is called after the loop is over, so at that time i will always be equal to the last value from the loop.
Using the i=i trick causes your function to store the current value of i at the time your lambda is defined, instead of waiting to look up the value of i later.
Change your lambda to lambda i=i: self.open_this(i).
This may look magical, but here's what's happening. When you use that lambda to define your function, the open_this call doesn't get the value of the variable i at the time you define the function. Instead, it makes a closure, which is sort of like a note to itself saying "I should look for what the value of the variable i is at the time that I am called". Of course, the function is called after the loop is over, so at that time i will always be equal to the last value from the loop.
Using the i=i trick causes your function to store the current value of i at the time your lambda is defined, instead of waiting to look up the value of i later.
This is how closures work in python. I ran into this problem myself once.
You could use functools.partial for this.
for i in range(3):
self.button.append(Button(self, text='Game '+str(i+1), command=partial(self.open_this, i)))
using for loop to create buttons (tkinter)
python - Looping Buttons in tkinter and function assignment - Stack Overflow
python - Iterating through buttons in tkinter - Stack Overflow
python - More efficient way to generate Tkinter buttons in loops - Code Review Stack Exchange
Videos
I am trying to have a quick way to implement buttons as I need 100 of it but when I implement it using forloop, on any button press the output is only (9, 9)
for x in range(10): #use this as row count
for y in range(10):
Button(root, text="", padx=px, pady=py, command=lambda: button_click((x, y), current_fleet)).grid(column=y, row=x, sticky=W)
Define a function to print the contents of one sheet, taking the sheet number as an argument. Then, use functools.partial to associate a command with each button:
def print_sheet(sheet_number):
...
for i in range(0, num_sheets):
an_sheet = ttk.Button(..., command = partial(print_sheet, i))
...
Here's a short but complete example of creating buttons in a loop:
import tkinter as tk
from tkinter import ttk
from functools import partial
root = tk.Tk()
def print_sheet(i):
print("printing sheet %d" % i)
for i in range(0, 5):
button = ttk.Button(root, text="Button %d" % i,
command=partial(print_sheet, i))
button.pack()
root.mainloop()
So you are asking about how to iterate through a set of functions and assign them?
You could use a dictionary
Example from my A-level computing coursework
self.screen_info = {"Email Customer": {"button_names": ["Enter Email"], "commands": [self.email_from_email]},
"Text Customer": {"button_names": ["Enter Number"], "commands": [self.text_from_number]},
"Backup Database": {"button_names": ["Choose Location"], "commands": [backup_database.backup]},
"Export Database": {"button_names": ["As .txt", "As .csv"], "commands": [lambda: export.main("txt"), lambda: export.main("csv")]}}
def populate(self):
for key in self.screen_info.keys():
self.screen_info[key]["parent"] = tk.Frame(self.screens, width = 300, height = 300, bg = "#E6E6FA")
self.screen_info[key]["parent"].place(relx = 0.5, rely = 0.5, anchor = tk.CENTER)
for num in range(len(self.screen_info[key]["button_names"])):
self.screen_info[key]["button_names"][num] = tk.Button(self.screen_info[key]["parent"],
width = 20,
text = self.screen_info[key]["button_names"][num],
font = ("Ariel", 11, "bold"),
command = self.screen_info[key]["commands"][num])
self.screen_info[key]["button_names"][num].place(relx = 0.5, y = 60 + num * 40, anchor = tk.CENTER)
So this will iterate through the dictionary creating everything and assign commands. I used lambda for 'Export Database' as the function requires a parameter and if i didn't use lambda then the function would run as soon as the program was launched
EDIT I overwrite each key-value in the dictionary with the associated widget but if you are not referring to them again you don't even need to set a variable, key to them