1
resposta

tkinter + subprocess + threading + pandas

Prezados, estou tendo o seguinte problema com um executável: Após o preencher os campos da tela e clicar nos botões "CLIQUE AQUI" da tela principal e "SIM" da janela de confirmação, a mensagem "Processando... Aguarde!" não muda (deveria aparecer em tempo real o valor de uma variável conforme o código itera) e, além disso, a tela inicial se abre novamente e mais nada acontece (é como se o código não rodasse). Paradoxalmente, o código funciona perfeitamente quando executado diretamente no VS Code.

Segue o print da planilha modelo abaixo: Insira aqui a descrição dessa imagem para ajudar na acessibilidade

Abaixo seguem as telas:

Tela Inicial (que abre após execução do executável e NOVAMENTE após o preenchimento dos campos -> CLIQUE AQUI -> SIM) Insira aqui a descrição dessa imagem para ajudar na acessibilidade

Tela com campos preenchidos Insira aqui a descrição dessa imagem para ajudar na acessibilidadeSegue o código de Frontend.py:

import pandas as pd
import tkinter as tk
from tkinter import messagebox
from PIL import Image, ImageTk
import os
import subprocess
import threading
import sys
import pandas

# Função de exibição do item que está sendo processado em tempo real
def update_label(item):
    root.after(0, lambda: status_label.config(text=f"Processando: {item}"))

# Função de exibição de erros
def show_error(message):
    messagebox.showerror("Erro", message)

# Função de processamento dos dados
def processar_dados():
    status_label.config(text="Processando... Aguarde!")
    script_path = os.path.abspath(os.path.join(diretorio, "Backend.py")).replace('\\', '/')
    command = [sys.executable, script_path, token, caminho]
    
    # Função para iniciar o subprocesso
    def run_process():
        global process
        process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)

        # Inicia a leitura da saída
        read_output()

    # Função para ler a saída do subprocesso
    def read_output():
        output = process.stdout.readline()
        if output:
            update_label(output.strip())
            # Agenda a próxima leitura
            root.after(100, read_output)
        elif process.poll() is not None:
            # Quando o processo terminar, lê stdout e stderr
            stdout, stderr = process.communicate()
            if process.returncode == 0:
                messagebox.showinfo("Informação", "Processamento concluído.")
            else:
                show_error(f"Erro: {stderr}")
            status_label.config(text="")

    # Execução do processo em um thread separado
    threading.Thread(target=run_process, daemon=True).start()

# Função de confirmação dos dados coletados
def abrir_confirmacao():
    mensagem = f"Confirma as informações abaixo?\n\nToken: {token}\n\nCaminho da Planilha: {caminho}"
    if messagebox.askyesno("Confirmação", mensagem):
        processar_dados()

# Função de coleta dos dados
def on_button_click():
    global token, caminho
    token = entry_token.get()
    caminho = entry_caminho.get().replace('"', '').replace("'", "").replace('\\', '/')
    abrir_confirmacao()

# Criação da janela principal
root = tk.Tk()
root.state('zoomed')
root.title("Exemplo")
root.configure(bg='#D3D3D3')

# Diretório dos arquivos
diretorio = os.path.dirname(os.path.abspath(__file__))

# Campo "Token"
label_token = tk.Label(root, text="Token do Usuário:", font=("Arial", 18), bg='#D3D3D3')
label_token.pack(pady=(100, 1))
entry_token = tk.Entry(root, width=35, font=("Arial", 14))
entry_token.pack(pady=(0, 30))

# Campo "Caminho da Planilha"
label_caminho = tk.Label(root, text="Caminho da Planilha", font=("Arial", 18), bg='#D3D3D3')
label_caminho.pack(pady=1)
entry_caminho = tk.Entry(root, width=65, font=("Arial", 14))
entry_caminho.pack(pady=(0, 100))

# Botão "Clique aqui"
button = tk.Button(root, text="CLIQUE AQUI", font=("Arial", 14, "bold"), command=on_button_click)
button.pack(pady=(20, 10))

# Label para exibir o status
status_label = tk.Label(root, text="", font=("Arial", 16), bg='#D3D3D3')
status_label.pack(pady=20)

# Iniciar o loop principal da interface
if __name__ == "__main__":
    root.mainloop()

O código Backend.py está na imagem a seguir (não coube escrevê-lo aqui): Insira aqui a descrição dessa imagem para ajudar na acessibilidade

1 resposta

Olá Ivan! Tudo bem?

Parece que o problema está relacionado à execução do subprocesso e à atualização da interface gráfica. Aqui estão algumas sugestões para resolver o problema:

  1. Verifique o Caminho do Script Backend: Certifique-se de que o caminho para o script Backend.py está correto. Você pode adicionar um print(script_path) para verificar se o caminho está sendo gerado corretamente.

  2. Saída do Subprocesso: Assegure-se de que o Backend.py está realmente gerando saída para o stdout, pois é isso que o read_output() está tentando ler. Se não houver saída, a função update_label() nunca será chamada.

  3. Verifique Erros no Subprocesso: Adicione um print(stderr) após process.communicate() para ver se há algum erro sendo gerado pelo Backend.py.

  4. Atualização da Interface: A função update_label() usa root.after(0, ...), que deve funcionar, mas você pode tentar usar root.after_idle(...) para garantir que a atualização ocorra assim que o loop de eventos estiver ocioso.

Espero que essas dicas ajudem a resolver o problema!

Bons estudos!

Caso este post tenha lhe ajudado, por favor, marcar como solucionado ✓.