FONHOME
FONHOME

Reputation: 3

Why does my root.after command not work in a loop?

import tkinter as tk

task = ["Sire, a villager is asking for additional rations, saying her children are starving"]


root = tk.Tk()
root.title("Test")
root.geometry("900x400")

x = tk.StringVar()

problem = tk.Label(root, textvariable=x, bg='white')
problem.place(rely = 0.5, relx= 0.5, anchor="center")

def show():
    for i in range(len(task[0])+1):
        root.after(i*500, lambda: x.set(task[0][0:i]))


b = tk.Button(root, text="Go", bg='white', command=show)
b.place(rely = 0.6, relx = 0.5, anchor="center")

root.configure(background='white')
root.mainloop()

When I run the program and click the button, the message only appears once instead of gradually.

Upvotes: 0

Views: 46

Answers (1)

Bryan Oakley
Bryan Oakley

Reputation: 386010

The reason is that you aren't creating a closure. Therefore, when the first call to after is triggered, the whole loop has finished and i will be set to the length of the string. Your lambda uses the current value of i, so it will always be the last value from the loop.

A really simple solution is to use the current value of i as the default value for a parameter to your lambda function, like this:

root.after(i*500, lambda i=i: x.set(task[0][0:i]))

However, that's way more complicated than it needs to be. after lets you add positional parameters so you don't need lambda at all. You can simply that statement down to this:

root.after(i*500, x.set, task[0][0:i])

Upvotes: 1

Related Questions