Resumo : neste tutorial, você aprenderá a exibir uma barra de progresso enquanto um thread está sendo executado em um aplicativo Tkinter.
Este tutorial pressupõe que você saiba como usar o after()
método e entenda como funcionam os threadings em Python. Além disso, você deve saber como alternar entre frames usando o método tkraise() .
Neste tutorial, você construirá um visualizador de imagens que mostra uma imagem aleatória de unsplash.com usando sua API.
Se você fizer uma solicitação HTTP para o seguinte endpoint de API:
https://source.unsplash.com/random/640x480
Linguagem de código: Python ( python )
…você obterá uma imagem aleatória com tamanho de 640×480.
A imagem a seguir mostra o aplicativo Image Viewer final:
Quando você clica no botão Próxima imagem , o programa chama a API de unsplash.com para baixar uma imagem aleatória e exibi-la na janela.
Também mostrará uma barra de progresso durante o download da imagem, indicando que o download está em andamento:
Para chamar a API, você usa o requests
módulo .
Primeiro, instale o requests
módulo se ele não estiver disponível no seu computador:
pip install requests
Linguagem de código: Python ( python )
Segundo, defina uma nova classe que herda da Thread
classe:
class PictureDownload(Thread):
def __init__(self, url):
super().__init__()
self.picture_file = None
self.url = url
def run(self):
""" download a picture and save it to a file """
# download the picture
response = requests.get(self.url, proxies=proxyDict)
picture_name = self.url.split('/')[-1]
picture_file = f'./assets/{picture_name}.jpg'
# save the picture to a file
with open(picture_file, 'wb') as f:
f.write(response.content)
self.picture_file = picture_file
Linguagem de código: Python ( python )
Nesta PictureDownload
classe, o run()
método chama a API usando o requests
módulo.
O run()
método baixa uma imagem e a salva na /assets/
pasta. Além disso, atribui o caminho da imagem baixada ao picture_file
atributo de instância.
Terceiro, defina uma App
classe que herde a Tk
classe. A App
classe representa a janela raiz.
A root
janela possui dois frames, um para exibir a barra de progresso e outro para mostrar o Canvas que contém a imagem baixada:
def __init__(self, canvas_width, canvas_height):
super().__init__()
self.resizable(0, 0)
self.title('Image Viewer')
# Progress frame
self.progress_frame = ttk.Frame(self)
# configrue the grid to place the progress bar is at the center
self.progress_frame.columnconfigure(0, weight=1)
self.progress_frame.rowconfigure(0, weight=1)
# progressbar
self.pb = ttk.Progressbar(
self.progress_frame, orient=tk.HORIZONTAL, mode='indeterminate')
self.pb.grid(row=0, column=0, sticky=tk.EW, padx=10, pady=10)
# place the progress frame
self.progress_frame.grid(row=0, column=0, sticky=tk.NSEW)
# Picture frame
self.picture_frame = ttk.Frame(self)
# canvas width & height
self.canvas_width = canvas_width
self.canvas_height = canvas_height
# canvas
self.canvas = tk.Canvas(
self.picture_frame,
width=self.canvas_width,
height=self.canvas_height)
self.canvas.grid(row=0, column=0)
self.picture_frame.grid(row=0, column=0)
Linguagem de código: Python ( python )
Ao clicar no Next Picture
botão, o handle_download()
método é executado:
def handle_download(self):
""" Download a random photo from unsplash """
self.start_downloading()
url = 'https://source.unsplash.com/random/640x480'
download_thread = PictureDownload(url)
download_thread.start()
self.monitor(download_thread)
Linguagem de código: Python ( python )
O handle_download()
método mostra o quadro de progresso chamando o start_downloading()
método e inicia a barra de progresso:
def start_downloading(self):
self.progress_frame.tkraise()
self.pb.start(20)
Linguagem de código: Python ( python )
Ele também cria um novo thread que baixa a imagem aleatória e chama o monitor()
método para monitorar o status do thread.
O seguinte mostra o monitor()
método:
def monitor(self, download_thread):
""" Monitor the download thread """
if download_thread.is_alive():
self.after(100, lambda: self.monitor(download_thread))
else:
self.stop_downloading()
self.set_picture(download_thread.picture_file)
Linguagem de código: Python ( python )
O monitor()
método verifica o status do thread. Se o thread estiver em execução, ele agenda outra verificação após 100 ms.
Caso contrário, o monitor()
método chama o stop_downloading()
método para parar a barra de progresso, exibir o quadro da imagem e mostrar a imagem.
O seguinte mostra o stop_downloading()
método:
def stop_downloading(self):
self.picture_frame.tkraise()
self.pb.stop()
Linguagem de código: Python ( python )
O seguinte mostra o programa Image Viewer completo:
import requests
import tkinter as tk
from threading import Thread
from PIL import Image, ImageTk
from tkinter import ttk
from proxies import proxyDict
class PictureDownload(Thread):
def __init__(self, url):
super().__init__()
self.picture_file = None
self.url = url
def run(self):
""" download a picture and save it to a file """
# download the picture
response = requests.get(self.url, proxies=proxyDict)
picture_name = self.url.split('/')[-1]
picture_file = f'./assets/{picture_name}.jpg'
# save the picture to a file
with open(picture_file, 'wb') as f:
f.write(response.content)
self.picture_file = picture_file
class App(tk.Tk):
def __init__(self, canvas_width, canvas_height):
super().__init__()
self.resizable(0, 0)
self.title('Image Viewer')
# Progress frame
self.progress_frame = ttk.Frame(self)
# configrue the grid to place the progress bar is at the center
self.progress_frame.columnconfigure(0, weight=1)
self.progress_frame.rowconfigure(0, weight=1)
# progressbar
self.pb = ttk.Progressbar(
self.progress_frame, orient=tk.HORIZONTAL, mode='indeterminate')
self.pb.grid(row=0, column=0, sticky=tk.EW, padx=10, pady=10)
# place the progress frame
self.progress_frame.grid(row=0, column=0, sticky=tk.NSEW)
# Picture frame
self.picture_frame = ttk.Frame(self)
# canvas width & height
self.canvas_width = canvas_width
self.canvas_height = canvas_height
# canvas
self.canvas = tk.Canvas(
self.picture_frame,
width=self.canvas_width,
height=self.canvas_height)
self.canvas.grid(row=0, column=0)
self.picture_frame.grid(row=0, column=0)
# Button
btn = ttk.Button(self, text='Next Picture')
btn['command'] = self.handle_download
btn.grid(row=1, column=0)
def start_downloading(self):
self.progress_frame.tkraise()
self.pb.start(20)
def stop_downloading(self):
self.picture_frame.tkraise()
self.pb.stop()
def set_picture(self, file_path):
""" Set the picture to the canvas """
pil_img = Image.open(file_path)
# resize the picture
resized_img = pil_img.resize(
(self.canvas_width, self.canvas_height),
Image.ANTIALIAS)
self.img = ImageTk.PhotoImage(resized_img)
# set background image
self.bg = self.canvas.create_image(
0,
0,
anchor=tk.NW,
image=self.img)
def handle_download(self):
""" Download a random photo from unsplash """
self.start_downloading()
url = 'https://source.unsplash.com/random/640x480'
download_thread = PictureDownload(url)
download_thread.start()
self.monitor(download_thread)
def monitor(self, download_thread):
""" Monitor the download thread """
if download_thread.is_alive():
self.after(100, lambda: self.monitor(download_thread))
else:
self.stop_downloading()
self.set_picture(download_thread.picture_file)
if __name__ == '__main__':
app = App(640, 480)
app.mainloop()
Linguagem de código: Python ( python )
Neste tutorial, você aprendeu como exibir uma barra de progresso que se conecta a um thread em execução para indicar que uma operação ainda está em andamento.