Tópico Tkinter

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 threadingmó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 Textwidget:

Para baixar uma página da web, usaremos o módulo de solicitações .

Primeiro, instale o requestsmódulo executando o seguinte comando:

pip install requestsLinguagem de código:  Python  ( python )

Em seguida, importe os módulos tkinter, threadinge requests:

import tkinter as tk
from tkinter import ttk
from tkinter.messagebox import showerror
from threading import Thread
import requestsLinguagem de código:  Python  ( python )

Em seguida, defina uma nova classe chamada AsyncDownloadque herda da Threadclasse:

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.textLinguagem de código:  Python  ( python )

Como AsyncDownloadfunciona a aula:

  • No __init__()método da AsyncDownloadclasse, inicializamos os atributos htmle url.
  • No run()método, chamamos a get()função get para baixar a página da web especificada pela URL e atribuir o código-fonte HTML ao htmlatributo.

Depois disso, crie a Appclasse herdada da Tkclasse. 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 Appclasse.

No handle_download()método, verificamos se a url foi fornecida. Se sim, criamos uma nova instância da AsyncDownloadclasse e iniciamos o thread. Além disso, desabilitamos o botão de download e limpamos o conteúdo do Textwidget.

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 Entrywidget 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(00)

        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(100lambda: 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.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *