By Rob via Discussions on Python.org at 05Apr2022 16:34:
Not that I want to hijack this thread in any way, but as I’ve a related
question, I thought it better to add to this thread, rather than create
a new one - forgive me if I’m wrong in my reasoning.
I’d have started a new topic named something like “Tkinter: why does
this mainloop call work?” or something like that. But no matter, we’re
here now.
I’m also learning how to implement a GUI front end with Tkinter and I’ve come across something that confuses me.
This code works fine…
#!/usr/bin/python3
# import tkinter module
from tkinter import *
[...]
# creating main tkinter window/toplevel
master = Tk()
[…]
infinite loop which can be terminated by keyboard
or mouse interrupt
mainloop()
... but my question is, why (in the above example, taken from a website for which I've not noted the URL) does the last line of code not read `master.mainloop()`
That would be because the tkinter
package provides a convenience
function named mainloop
for people not wanting to bother typing
master.mainloop()
No, really, it does exactly that!
Having a gander at the tkinter source (you’ll have a copy on your
machine too in the Python standard library) we find in
tkinter/__init__.py
this code:
def mainloop(n=0):
"""Run the main loop of Tcl."""
_get_default_root('run the main loop').tk.mainloop(n)
and higher up this code:
def _get_default_root(what=None):
if not _support_default_root:
raise RuntimeError("No master specified and tkinter is "
"configured to not support default root")
if _default_root is None:
if what:
raise RuntimeError(f"Too early to {what}: no default root window")
root = Tk()
assert _default_root is root
return _default_root
and above that this:
_support_default_root = True
_default_root = None
I expect that when you created master
the global
tkinter._default_root
became set to that top level widget/app. When you
call mainloop
(which got imports by your “from tkinter import *
”) it
finds that widget/app, and calls its .mainloop()
.
The script works either way, but in what situation would one simply use
mainloop()
as opposed to, some_name.mainloop()
and is it ‘best
practice’ to always use some_name.mainloop()
Personally I would use some_name.mainloop()
.
I can imagine some handler function somewhere might not have access to
the top level widget. There, it might be sensible to call it this way.
So it is not without value.
It is, in Tk at least, meaningful to run the mainloop in various places
- all it does is process events and call their handles, which is what
makes the GUI operate.
Specificly, there’s a method named wait_visibility
you can call which
blocks your code until a widget is mapped and rendered. But wait!
Wouldn’t that block the entire GUI? This function has to work by itself
calling the mainloop until that widget is ready, then leaving the loop
and returning to the code which called it, which in turn continues and
resumes the “main” mainloop later.
I’d expect all of Tk’s wait_*
methods to operate in this fashion.
The universal widget methods are documented here:
https://tkdocs.com/shipman/universal.html
The wait_visibility
method is listed in there.
Cheers,
Cameron Simpson cs@cskk.id.au