This GUI thread story is prone to change over time, but it imposes a few structural
constraints on programs. For example, because spawned threads cannot usually per-
form GUI processing, they must generally communicate with the main thread using
global variables or shared mutable objects such as queues, as required by the applica-
tion. A spawned thread which watches a socket for data, for instance, might simply set
global variables or append to shared queues, which in turn triggers GUI changes in the
main thread’s periodic after event callbacks. The main thread’s timer events process
the spawned thread’s results.
Although some GUI operations or toolkits may support multiple threads better than
others, GUI programs are generally best structured as a main GUI thread and non-GUI
“worker” threads this way, both to avoid potential collisions and to finesse the thread
safety issue altogether. The PyMailGUI example later in the book, for instance, will
collect and dispatch callbacks produced by threads and stored on a queue.
Also remember that irrespective of thread safety of the GUI itself, threaded GUI pro-
grams must follow the same principles of threaded programs in general—as we learned
in Chapter 5, such programs must still synchronize access to mutable state shared
between threads, if it may be changed by threads running in parallel. Although a
producer/consumer thread model based upon queues can alleviate many thread issues
for the GUI itself, a program that spawns non-GUI threads to update shared informa-
tion used by the GUI thread may still need to use thread locks to avoid concurrent
update issues.
We’ll explore GUI threading in more detail in Chapter 10, and we’ll meet more realistic
threaded GUI programs in Part IV, especially in Chapter 14’s PyMailGUI. The latter,
for instance, runs long-running tasks in threads to avoid blocking the GUI, but both
restricts GUI updates to the main thread and uses locks to prevent overlap of operations
that may change shared caches.
Using the after Method
Of all the event tools in the preceding list, the after method may be the most interesting.
It allows scripts to schedule a callback handler to be run at some time in the future.
Though a simple device, we’ll use this often in later examples in this book. For instance,
in Chapter 11, we’ll meet a clock program that uses after to wake up 10 times per
second and check for a new time, and we’ll see an image slideshow program that uses
after to schedule the next photo display (see PyClock and PyView). To illustrate the
basics of scheduled callbacks, Example 9-27 does something a bit different.
Example 9-27. PP4E\Gui\Tour\alarm.py
flash and beep every second using after() callback loop
from tkinter import *
class Alarm(Frame):
Time Tools, Threads, and Animation | 585