liveBook · Manning

After

As explained in Python Concurrency with asyncio

after is a Tkinter widget method that schedules a callback to run after a specified time interval in the GUI event loop.

Tkinter’s after method schedules a callback to run after a specified interval without blocking the GUI event loop. It is useful when a responsive interface must periodically check progress while asynchronous work runs elsewhere. section 7.4.2

In a URL stress tester, the Tkinter event loop remains in the main thread while an asyncio loop runs in another thread. A scheduled callback can refresh the interface as requests complete, avoiding the hang caused by calling asyncio.run from the GUI. section 7.4.2

Polling a URL stress test

Use after for recurring progress checks: let the interface update its progress bar and respond to cancellation while the asyncio stress test continues independently. section 7.4.2

Listing 7.14 The Tkinter GUI
from queue import Queue
from tkinter import Tk
from tkinter import Label
from tkinter import Entry
from tkinter import ttk
from typing import Optional
from chapter_07.listing_7_13 import StressTest
 
 
class LoadTester(Tk):
 
    def __init__(self, loop, *args, **kwargs):                             #1
        Tk.__init__(self, *args, **kwargs)
        self._queue = Queue()
        self._refresh_ms = 25
 
        self._loop = loop
        self._load_test: Optional[StressTest] = None
        self.title('URL Requester')
 
        self._url_label = Label(self, text="URL:")
        self._url_label.grid(column=0, row=0)
 
        self._url_field = Entry(self, width=10)
        self._url_field.grid(column=1, row=0)
 
        self._request_label = Label(self, text="Number of requests:")
        self._request_label.grid(column=0, row=1)
 
        self._request_field = Entry(self, width=10)
        self._request_field.grid(column=1, row=1)
 
        self._submit = ttk.Button(self, text="Submit", command=self._start)#2
        self._submit.grid(column=2, row=1)
 
        self._pb_label = Label(self, text="Progress:")
        self._pb_label.grid(column=0, row=3)
 
        self._pb = ttk.Progressbar(self, orient="horizontal", length=200, mode="determinate")
        self._pb.grid(column=1, row=3, columnspan=2)
    def _update_bar(self, pct: int):                                       #3
        if pct == 100:
            self._load_test = None
            self._submit['text'] = 'Submit'
        else:
            self._pb['value'] = pct
            self.after(self._refresh_ms, self._poll_queue)
 
    def _queue_update(self, completed_requests: int, total_requests: int): #4
        self._queue.put(int(completed_requests / total_requests * 100))
 
    def _poll_queue(self):                                                 #5
        if not self._queue.empty():
            percent_complete = self._queue.get()
            self._update_bar(percent_complete)
        else:
            if self._load_test:
                self.after(self._refresh_ms, self._poll_queue)
 
    def _start(self):                                                      #6
        if self._load_test is None:
            self._submit['text'] = 'Cancel'
            test = StressTest(self._loop,
                              self._url_field.get(),
                              int(self._request_field.get()),
                              self._queue_update)
            self.after(self._refresh_ms, self._poll_queue)
            test.start()
            self._load_test = test
        else:
            self._load_test.cancel()
            self._load_test = None
            self._submit['text'] = 'Submit'

The Tkinter GUI listing provides the surrounding interface architecture for scheduling refresh work without blocking user interaction. section 7.4.2

How Python Concurrency with asyncio covers it

How deep it goes
Defines delayed callbacks and applies them to GUI progress polling, but does not detail callback internals.
Examples
Uses a URL stress tester that updates a progress bar while requests execute in an asyncio event loop.
What it assumes
Assumes basic Tkinter widgets and event loops while introducing coordination between Tkinter and asyncio.
What you can do after
Apply it via Tkinter to schedule non-blocking interface updates during long-running work.
How it connects
Connects Tkinter’s event loop with callbacks, threads, asyncio, progress bars, and cancellation.

This explainer was generated by Manning's knowledge graph from the text of Python Concurrency with asyncio. The section links point to the parts of the book it draws on.