Skip to content Skip to sidebar Skip to footer

Tkinter Only Calls After_idle Once

I am new to Tkinter, so I apologize if this is easy, but I have search for a couple of hours and can't figure it out. What I want to do is after the mainloop is idle, I always wan

Solution 1:

@user1763510, notice that in Bryan Oakley's answer, he has checkForGroupUpdates call self.after again. This is because self.after only does a single call, so getting repeated calls requires having it call itself within the function that gets called by the first call. This way, it keeps repeatedly calling itself.

The same goes for the after_idle() function. You have to have checkForGroupUpdates call after_idle() again at the bottom.

Here is the documentation for after, after_idle, etc. There is even a little example in the after description, which makes it all clear.

Documentation: http://effbot.org/tkinterbook/widget.htm

Example from link above, under the afterdescription:

#Method 1classApp:def__init__(self, master):
        self.master = master
        self.poll() # start pollingdefpoll(self):
        ... do something ...
        self.master.after(100, self.poll)

To use after_idle instead, it would look like this:

#Method 2classApp:def__init__(self, master):
        self.master = master
        self.poll() # start pollingdefpoll(self):
        ... do something ...
        self.master.update_idletasks()
        self.master.after_idle(self.poll)

Notice the addition of the self.master.update_idletasks() line. This draws the GUI and handles button presses and things. Otherwise, after_idle() will suck up all resources and not let the GUI self-update properly in the mainloop().

An alternative to using

self.master.update_idletasks()
        self.master.after_idle(self.poll)

is to use:

#Method 3self.master.update_idletasks()
        self.master.after(0, self.poll)

Using self.master.after(0, self.poll) is my preferred technique, as it allows me to easily change the 0 to something else if I decide I don't need to run self.poll constantly. By increasing the delay time to at least 1 ms, you no longer need to call self.master.update_idletasks() at all. So, this works too:

#Method 4self.master.after(1, self.poll)

Also notice that for all examples above, calling self.poll() in the __init__ function is what kicks it all off, and storing master into self.master is necessary simply so that inside poll you can call the after or after_idle function via self.master.after_idle, for example.

Q: Is this stable/does it work? A: I ran a test code using Method 3 just above for ~21 hrs, and it ran stably the whole time, allowing the GUI to be usable and all.

Q: What is the speed comparison for each method above? A:

  • Method 1: (I didn't speed test it)
  • Method 2: ~0.44 ms/iteration
  • Method 3: ~0.44 ms/iteration
  • Method 4: ~1.61 ms/iteration

Q: Which is my preferred method? A: Method 3 or 4.

Solution 2:

Instead of calling the function all the time when the app is idle, you should just call it once every fraction of a second. For example, if you want to check 10 times every second you would do something like this:

defcheckForGroupUpdates(self):
    <do whatever you want>
    self.after(100, self.checkForGroupUpdates)

Once you call that function once, it will arrange for itself to be called again in 100ms. This will continue until the program exits. If the program goes "non-idle" (ie: while responding to a button click), this function will pause since tkinter is single-threaded. Once the program goes idle again, the check will continue.

Post a Comment for "Tkinter Only Calls After_idle Once"