On the nature of GUI programs
This is based on answers (1, 2) I gave on stackoverflow. That answer is specific
to the tkinter
toolkit that comes with Python. The principles apply to
other GUI toolkits and languages as well but the terminology used (like
mainloop
and idle task) may be different.
GUI toolkits like tkinter
are event-driven. To work properly, the
mainloop
must continuously be able to process keyboard and mouse events.
When it is not processing events, it will start scheduled idle tasks.
So they work quite differently from normal Python scripts that just run from top to bottom.
A tkinter
program runs within the “mainloop“. So there are only three
things you do before starting the mainloop.
- Create a window with some widgets on it.
- Create objects (variables) that hold program state.
- Define functions that can be run from the
mainloop
as callbacks or idle tasks.
Usually I tend to wrap the creation of the window and widgets up in
a function. This makes the program easier to read. We need to keep
references to some of the widgets (e.g. to get the text from an Entry
).
So those I tend to put in a types.SimpleNamespace
that is returned by the
function. This makes it easy to access them later.
With regard to (2), I like to wrap those up in a types.SimpleNamespace
as
well for the same reason.
A callback is called from within the mainloop
in response to activating
a control (like clicking on a button). An idle task is started by the system
after a specified number of milliseconds when the system is not busy
processing events. You can schedule idle tasks with the Tk.after()
method.
Basically, the callbacks and idle tasks are your program.
It is important to understand that the callbacks and idle tasks both interrupt
the mainloop
. As long as a callback or idle task is running, the
mainloop
is not processing events, and your GUI is unresponsive.
This means that you cannot have long-running loops in a callback or idle task.
Luckily, in Python 3 tkinter is supposed to be thread-safe provided that the
tcl/tk is uses was built with support for threads.
That means you can use threads for long-running tasks, and it should be safe
to call tkinter
functions and methods from such a thread.
For comments, please send me an e-mail.
Related articles
- Profiling Python scripts(6): auto-orient
- Profiling with pyinstrument
- From python script to executable with cython
- On Python speed
- Python 3.11 speed comparison with 3.9