0

I would like to have a window running and a process that runs in the background every 15 seconds. So far, I've learned that the tkinter after method is a good way to do this, however I'm having trouble spacing the function calls out every 15 seconds. Here's an example of my current calling of after:

import tkinter as tk

class Dummy():
    def __init__(self):
        self.top = tk.Tk()
        self.open_flag = True
        # set up the window layout, etc

    def dummy_function(self):
        print("Updating...")

    def show(self):
        while self.open_flag:
            self.top.update_idletasks()
            self.top.update()
            self.top.after(15000, self.dummy_function)

I found that the above script would create the window, wait 15 seconds, and then execute a whole slew of calls to the dummy_function in rapid sequence. After further research, I think this is because after just schedules the provided function to get called after the provided delay and then it moves on without blocking. This would seem to cause the exact scenario that I talked about above.

I've tried calling time.sleep() after the last line there (inside the while loop) in order to space out the calls of after, but this gives me the colorful pinwheel of death on macOS and makes the entire window non-functional. Any ideas on how to space out these dummy_function calls?

ThirteenthWolf
  • 336
  • 3
  • 9
  • 1
    _"After further research, I think this is because after just schedules the provided function to get called after the provided delay and then it moves on without blocking."_ correct, that is its documented behavior. – Bryan Oakley Nov 20 '20 at 21:56

1 Answers1

1

This answer may provide some additional info, but to confirm what's happening in your case:

The tk window needs to constantly be updated. You can either do this by calling window.mainloop() which (for the sake of simplicity) does the same as this:

while True:
    window.update()

If you need to perform more actions between each update, then you can essentially do what you've done and create your own while loop, which calls window.update() every frame (in your case its self.top.update()).

By using time.sleep() in that while loop, you end up only calling .update() once every 15 seconds! Which is no where near enough for tk to handle everything and keep the window responsive (since it can only react to user input once every 15 seconds).


Typical use of the .after() method is as follows:

import tk

window = tk.Tk()

def func():
    # ... some code ...
    window.after(15*1000, func)

window.after(15*1000, func)
tk.mainloop()

This essentially means that the func function is run 15 seconds after the previous call, and will give the results you're after.

dwb
  • 2,136
  • 13
  • 27