Tkinter Only Calls After_idle Once
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 after
description:
#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"