Resumo : neste tutorial, você aprenderá como usar vários threads em aplicativos Tkinter para torná-los mais responsivos.
Quando usar Thread em aplicativos Tkinter
Em uma aplicação Tkinter, o loop principal deve sempre começar no thread principal. É responsável por tratar eventos e atualizar a GUI.
Se você tiver uma operação em segundo plano que leva tempo, execute-a em um thread separado .
Caso contrário, o aplicativo não responderá. Na pior das hipóteses, ele irá congelar enquanto a operação estiver em execução.
Para criar e controlar vários threads em aplicativos Tkinter, você pode usar o módulo Python .threading
O threading
módulo está incluído na biblioteca padrão do Python, portanto você não precisa instalá-lo.
Para obter mais informações sobre como usar o módulo threading, você pode seguir o tutorial de threading Python .
Exemplo de thread Tkinter
Construiremos um programa simples que baixa uma página da Web especificada por uma URL e exibe seu conteúdo em um Text
widget:
Para baixar uma página da web, usaremos o módulo de solicitações .
Primeiro, instale o requests
módulo executando o seguinte comando:
pip install requests
Linguagem de código: Python ( python )
Em seguida, importe os módulos tkinter
, threading
e requests
:
import tkinter as tk
from tkinter import ttk
from tkinter.messagebox import showerror
from threading import Thread
import requests
Linguagem de código: Python ( python )
Em seguida, defina uma nova classe chamada AsyncDownload
que herda da Thread
classe:
class AsyncDownload(Thread):
def __init__(self, url):
super().__init__()
self.html = None
self.url = url
def run(self):
response = requests.get(self.url)
self.html = response.text
Linguagem de código: Python ( python )
Como AsyncDownload
funciona a aula:
- No
__init__()
método daAsyncDownload
classe, inicializamos os atributoshtml
eurl
. - No
run()
método, chamamos aget()
função get para baixar a página da web especificada pela URL e atribuir o código-fonte HTML aohtml
atributo.
Depois disso, crie a App
classe herdada da Tk
classe. A classe App representa a janela raiz.
A janela raiz consiste em três quadros que contêm todos os widgets. Não vamos nos concentrar em como criar widgets e colocá-los na janela usando o gerenciador de geometria de grade .
Ao clicar no botão de download, o programa executa o handle_download()
método da App
classe.
No handle_download()
método, verificamos se a url foi fornecida. Se sim, criamos uma nova instância da AsyncDownload
classe e iniciamos o thread. Além disso, desabilitamos o botão de download e limpamos o conteúdo do Text
widget.
Além disso, chamamos o monitor()
método para monitorar o status do thread.
def handle_download(self):
url = self.url_var.get()
if url:
self.download_button['state'] = tk.DISABLED
self.html.delete(1.0, "end")
download_thread = AsyncDownload(url)
download_thread.start()
self.monitor(download_thread)
else:
showerror(title='Error',
message='Please enter the URL of the webpage.')
Linguagem de código: Python ( python )
No monitor()
método, agendamos uma ação que executará o monitor()
método após 100ms se o thread ainda estiver ativo.
Se o download for concluído, atualizamos o conteúdo do Entry
widget e reativamos o botão de download:
def monitor(self, thread):
if thread.is_alive():
# check the thread every 100ms
self.after(100, lambda: self.monitor(thread))
else:
self.html.insert(1.0, thread.html)
self.download_button['state'] = tk.NORMAL
Linguagem de código: Python ( python )
Por fim, execute o loop principal da aplicação:
if __name__ == "__main__":
app = App()
app.mainloop()
Linguagem de código: Python ( python )
A seguir mostramos o programa completo:
import tkinter as tk
from tkinter import ttk
from tkinter.messagebox import showerror
from threading import Thread
import requests
class AsyncDownload(Thread):
def __init__(self, url):
super().__init__()
self.html = None
self.url = url
def run(self):
response = requests.get(self.url)
self.html = response.text
class App(tk.Tk):
def __init__(self):
super().__init__()
self.title('Webpage Download')
self.geometry('680x430')
self.resizable(0, 0)
self.create_header_frame()
self.create_body_frame()
self.create_footer_frame()
def create_header_frame(self):
self.header = ttk.Frame(self)
# configure the grid
self.header.columnconfigure(0, weight=1)
self.header.columnconfigure(1, weight=10)
self.header.columnconfigure(2, weight=1)
# label
self.label = ttk.Label(self.header, text='URL')
self.label.grid(column=0, row=0, sticky=tk.W)
# entry
self.url_var = tk.StringVar()
self.url_entry = ttk.Entry(self.header,
textvariable=self.url_var,
width=80)
self.url_entry.grid(column=1, row=0, sticky=tk.EW)
# download button
self.download_button = ttk.Button(self.header, text='Download')
self.download_button['command'] = self.handle_download
self.download_button.grid(column=2, row=0, sticky=tk.E)
# attach the header frame
self.header.grid(column=0, row=0, sticky=tk.NSEW, padx=10, pady=10)
def handle_download(self):
url = self.url_var.get()
if url:
self.download_button['state'] = tk.DISABLED
self.html.delete(1.0, "end")
download_thread = AsyncDownload(url)
download_thread.start()
self.monitor(download_thread)
else:
showerror(title='Error',
message='Please enter the URL of the webpage.')
def monitor(self, thread):
if thread.is_alive():
# check the thread every 100ms
self.after(100, lambda: self.monitor(thread))
else:
self.html.insert(1.0, thread.html)
self.download_button['state'] = tk.NORMAL
def create_body_frame(self):
self.body = ttk.Frame(self)
# text and scrollbar
self.html = tk.Text(self.body, height=20)
self.html.grid(column=0, row=1)
scrollbar = ttk.Scrollbar(self.body,
orient='vertical',
command=self.html.yview)
scrollbar.grid(column=1, row=1, sticky=tk.NS)
self.html['yscrollcommand'] = scrollbar.set
# attach the body frame
self.body.grid(column=0, row=1, sticky=tk.NSEW, padx=10, pady=10)
def create_footer_frame(self):
self.footer = ttk.Frame(self)
# configure the grid
self.footer.columnconfigure(0, weight=1)
# exit button
self.exit_button = ttk.Button(self.footer,
text='Exit',
command=self.destroy)
self.exit_button.grid(column=0, row=0, sticky=tk.E)
# attach the footer frame
self.footer.grid(column=0, row=2, sticky=tk.NSEW, padx=10, pady=10)
if __name__ == "__main__":
app = App()
app.mainloop()
Linguagem de código: Python ( python )
Resumo
- Execute tarefas em segundo plano em threads separados para tornar o aplicativo Tkinter responsivo.