How it works...

Progressbar is a themed widget included in the tkinter.ttk module. We will dive into this module in Chapter 8, Themed Widgets, to explore the new widgets that it defines, but so far we only need to use Progressbar as a regular widget.

We also need to import the queue module, which defines synchronized collections such as Queue. Synchronicity is an important topic in multithreaded environments, because an unexpected result might occur if shared resources are accessed at exactly the same time—we define this unlikely but possible scenarios as a race condition.

With these additions, our App class contains these new statements:

# ...
import queue
import tkinter.ttk as ttk

class App(tk.Tk):
def __init__(self):
# ...
self.queue = queue.Queue()
self.progressbar = ttk.Progressbar(self, length=300,
orient=tk.HORIZONTAL)

Like previous examples, the start_action() method starts a thread, passing the queue and the number of steps that will simulate the long running task:

    def start_action(self):
self.button.config(state=tk.DISABLED)
thread = AsyncAction(self.queue, 20)
thread.start()
self.poll_thread(thread)

Our AsyncAction subclass defines a custom constructor to receive these parameters, which will later be used in the run() method:

class AsyncAction(threading.Thread):
def __init__(self, queue, steps):
super().__init__()
self.queue = queue
self.steps = steps

def run(self):
for _ in range(self.steps):
time.sleep(1)
self.queue.put(1 / self.steps)

The loop suspends the execution of the thread for 1 second and adds the increment to the queue as many times as indicated in the steps attribute.

The item added to the queue is retrieved from the application instance by reading the queue from check_queue():

    def check_queue(self):
while self.queue.qsize():
try:
step = self.queue.get(0)
self.progressbar.step(step * 100)
except queue.Empty:
pass

The following method is periodically called from poll_thread(), which polls the thread status and schedules itself again with after() until the thread completes its execution:

    def poll_thread(self, thread):
self.check_queue()
if thread.is_alive():
self.after(100, lambda: self.poll_thread(thread))
else:
self.button.config(state=tk.NORMAL)
mb.showinfo("Done!", "Async action completed")
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset