I asked a similar question about two years ago when I was trying to emulate LEDs on a Tkinter canvas. The solution then was to use the canvas after() method instead of the sleep() function to introduce a delay between widget updates.
Since then, I have discovered the tk_tools module which has a buit-in function to create LEDs, great! But I now have the same issue as before, which is: How to have a 1-second delay between the turning on (change to green) of each LED?
What actually happens when running the code below is that the LEDs are displayed in their OFF state (gray), then when I click the 'Start' button, there's a 4-second delay after which all LEDs turn on simultaneously.
Thank you. Johnnym
# LED array simulation
from tkinter import *
import tk_tools as tkt
from time import *
# turn on LEDs (change to green) with a 1-second delay between each
def turn_on():
for led in range(4):
led_array[led].to_green()
sleep(1)
# list to hold a 4-LED array
led_array = []
# GUI
root = Tk()
# create 4 LED widgets, store them in led_array[], display them
for i in range(4):
led_array.append(tkt.Led(root, size=30))
led_array[i].grid(row=0, column=i)
# create button to initiate LED turn-on sequence
start = Button(root, text='Start', padx=20, command=turn_on)
start.grid(row=1, columnspan=4)
root.mainloop()
It's best to avoid sleep which stops the application and use after
. Either chain the calls to the after callback so each one calls the next or call them in a loop for each led but at 1, 2, 3 then 4 seconds delay.
Chained version:
# LED array simulation
from tkinter import *
import tk_tools as tkt
# list to hold a 4-LED array
led_array = []
# GUI
root = Tk()
# create 4 LED widgets, store them in led_array[], display them
for i in range(4):
led_array.append(tkt.Led(root, size=30))
led_array[i].grid(row=0, column=i)
# Both answers are common to here.
def on_after( led_list ):
led_list[0].to_green() # Set first item in the list.
if len( led_list ) > 1:
# Call on_after again with a shortened list.
root.after( 1000, on_after, led_list[1:] )
else:
# Enable the start button
start.config( state = NORMAL )
# turn on LEDs (change to green) with a 1-second delay between each
def turn_on():
start.config( state = DISABLED ) # Disable the button
root.after( 1000, on_after, led_array)
# create button to initiate LED turn-on sequence
start = Button(root, text='Start', padx=20, command=turn_on)
start.grid(row=1, columnspan=4)
root.mainloop()
Looped version:
# Both answers are common to here.
def on_after( led ):
led.to_green()
def enable():
start.config( state = NORMAL )
# turn on LEDs (change to green) with a 1-second delay between each
def turn_on():
start.config( state = DISABLED ) # Disable the button
for ix, led in enumerate( led_array ):
# Call on_after 4 times with 1 to 4 second delays
root.after( 1000 * (1+ix), on_after, led )
root.after( 1000*(ix+1), enable )
# create button to initiate LED turn-on sequence
start = Button(root, text='Start', padx=20, command=turn_on)
start.grid(row=1, columnspan=4)
root.mainloop()
I'd probably use the chained version although in this context the looped version is probably easier to understand.