-1

It's a pretty simple problem already explained in my title, here's the code:

def flash():
    import time
    for i in range(1,len(says)):
        label5.config(bg=says[i])
        time.sleep(1)

time.sleep, in this case, does absolutely nothing but delays my program for a couple of seconds, and then only shows the final product of the function and skips the whole process which is very important to me.

cezar
  • 11,616
  • 6
  • 48
  • 84
Treemur
  • 3
  • 1
  • 1
    You can't block the tkinter UI thread using `sleep`. I think it has its own delay mechanism that you can use. – Carcigenicate Feb 14 '19 at 13:17
  • Possible duplicate of [Python time.sleep](https://stackoverflow.com/questions/10393886/python-time-sleep) – Carcigenicate Feb 14 '19 at 13:19
  • That's a loose duplicate, but it will likely answer your question. – Carcigenicate Feb 14 '19 at 13:19
  • How do I use it in this case? What goes before .after? – Treemur Feb 14 '19 at 13:21
  • @Treemur You may need to make `flash` recursive or something similar. You could give `flash` an argument containing the remaining `says` items, then do something like `def flash(rest): label5.config(bg=says[0]); label5.after(1000, lambda: flash(rest[:1]))`, then handle `rest` being empty. Then call `flash` as `flash(says)`. – Carcigenicate Feb 14 '19 at 13:26
  • _"time.sleep ... does absolutely nothing but delays my program for a couple of seconds"_ - that's precisely what it's supposed to do. – Bryan Oakley Feb 14 '19 at 14:00

1 Answers1

1

In Tkinter you should use after instead of sleep to schedule functions for later execution (in milliseconds). In your case, you could try something like this.

def flash():
    for i in range(1,len(says)):
        label5.after(i*1000, lambda i=i: label5.config(bg=says[i]))

import tkinter as tk
says = ["white", "red", "green", "blue"]
root = tk.Tk()
label5 = tk.Button(root, text="Flashing label", command=flash)
label5.pack()
root.mainloop()

Note that this does not delay the execution of the loop itself but just schedules the label to be updated at different times in the future. If there is more code inside the loop that should co-occur with the color changes, you'd have to put that into the callback function, as well, which, of course, can also be a regular def function instead of lambda. (About the lambda i=i: see here)

tobias_k
  • 81,265
  • 12
  • 120
  • 179
  • This is far above my level, but I just copied your code and it worked, even though I really can't tell why. Thanks! – Treemur Feb 14 '19 at 13:56
  • @Treemur Nah, it's just a function that calls another function after some time, just like `command` for a button. Maybe you haven't used `lambda` yet, but that's basically just an anonymous in-line function. – tobias_k Feb 14 '19 at 14:05
  • @Treemur What exactly here are you having trouble with? Is it the lambda? All of this can be explained easily if you're having trouble. It's important to understand what your code does. Using code that you don't understand just leads to problems later. – Carcigenicate Feb 14 '19 at 15:49
  • @carcigenicate yes, the lambda, and im not quite sure what ".pack" means. – Treemur Feb 14 '19 at 16:45
  • @Treemur A lambda is just a function without a name. `def f(n): return n + 1` could also be written as `lambda n: n + 1`. They're for when you want to pass a function that isn't defined elsewhere already. And I believe `pack` tells tkinter to reevaluate the space that each element takes up. – Carcigenicate Feb 14 '19 at 16:56
  • @Treemur You don't really have to worry about the code below the function. That's just for testing the function. You just use whatever you have as your UI. – tobias_k Feb 14 '19 at 17:03