2

I have to stop a loop and resume after many seconds. I tried to use after(), but the loop don't freeze. And when I use time.sleep() (works out tkinter), tkinter freeze. Have another way or a function equivalent time.sleep() without freeze.

code:

for message in listOfMessages:
    time.sleep(message.time)
    #manipulate message
    #change text widget

This will freeze my tkinter app.

I tried to use after() but message.time is a float: 0.5054564 to 1.5234244. It's random. And after supports only int. I can't convert to int, because low numbers make differents. And if i convert 0.52342342 in int: 523... i lost the others 42342

and this dont work too:

def changes(#values):
    #manipulate message
    #change text widget

for message in listOfMessages:
    app.after(message.time, lambda: changes(#values))

Have another function equivalent time.sleep thats not freeze tkinter and is different that after()? If not, have another way to do this? Thanks for attention.

1
  • What does message.time represent -- milliseconds? Seconds? Minutes? Commented Oct 16, 2015 at 17:22

1 Answer 1

3

To create an analog of:

for message in listOfMessages:
    time.sleep(message.time)
    change(message)

in tkinter:

def update_widget(app, messages):
    message = next(messages, None)
    if message is None: # end of the loop
        return
    delay = int(message.time * 1000) # milliseconds
    app.after(delay, change, message) # execute body
    app.after(delay, update_widget, app, messages) # next iteration

update_widget(app, iter(listOfMessages))

If you want to wait until change(message) finishes before continuing the loop:

def iterate(message, app, messages):
    change(message)
    update_widget(app, messages)

def update_widget(app, messages):
    message = next(messages, None)
    if message is None: # end of the loop
        return
    delay = int(message.time * 1000) # milliseconds
    app.after(delay, iterate, message, app, messages)

update_widget(app, iter(listOfMessages))
9
  • this works, but when message have a time != 0, error appears: tkinter.TclError: bad argument "507.478125": must be cancel, idle, info, or an integer
    – Radagast
    Commented Oct 16, 2015 at 18:21
  • @ArnaldoBadin: if message.time is a float then coerce the delay into integer. I've updated the answer.
    – jfs
    Commented Oct 16, 2015 at 18:24
  • Bug appears, not a error, but I have delay in lasts messages. Have a way to self.after read float? like 507.478125?
    – Radagast
    Commented Oct 16, 2015 at 18:44
  • @ArnaldoBadin: delay is in milliseconds i.e., the scheduling precision is probably worse than that and therefore accepting a float wouldn't help anyway. Make sure you don't call functions that may block in change(message). Use threads, separate processes to offload blocking calls. btw., are you sure you want to wait 500 seconds (almost 10 minutes)?
    – jfs
    Commented Oct 16, 2015 at 18:54
  • 1
    @ArnaldoBadin: It indicates that the issue is that you call a blocking function in your code. Timer() creates a new thread that allows you to avoid unnecessary delay due to the blocking call. Otherwise, there is no reason to expect a better precision from Timer() than from app.after().
    – jfs
    Commented Oct 16, 2015 at 21:04

Not the answer you're looking for? Browse other questions tagged or ask your own question.