Barra de progreso TTK bloqueada al enviar correo electrónico

Estoy escribiendo una aplicación en python usando tkinter. En esta aplicación estoy intentando enviar un lote de correos electrónicos y quiero mostrar una barra de progreso mientras se envían. Puedo crear la barra de progreso e iniciarla, pero cuando se envían los correos electrónicos, la barra simplemente se detiene (si se inicia mucho antes de que se envíen los correos electrónicos, quiero iniciar la barra justo antes de enviar los correos electrónicos pero solo cuelga y nada se mueve en la barra cuando lo hago así.

startProgressBar() sendEmails() stopProgressBar() 

He intentado poner el envío de correos electrónicos en un hilo aparte, pero no parece que esté teniendo suerte. Estoy usando el módulo de subprocesamiento de alto nivel. ¿Hay alguna sugerencia sobre qué hacer? Tal vez no estoy obteniendo la parte de rosca correcta. Estoy usando el smtplib para enviar correos electrónicos.

Esta es una pregunta antigua, pero la receta del código al que me refiero me ha ayudado con un concepto similar, así que pensé que debería compartirse.

Este tipo de problema necesita utilizar hilos para que podamos completar la tarea de actualizar la GUI y hacer la tarea real (como enviar correos electrónicos). Eche un vistazo a esta receta de código de Active State. Creo que es exactamente lo que está buscando como ejemplo de subprocesos y pasar información entre subprocesos (a través de una cola).

Intento resaltar las partes importantes de la receta del código. No incluyo la configuración de la barra de progreso en sí, sino la estructura general del código y la obtención / configuración de una cola.

 import Tkinter import threading import Queue class GuiPart: def __init__(self, master, queue, endCommand): self.queue = queue # Do GUI set up here (ie draw progress bar) # This guy handles the queue contents def processIncoming(self): while self.queue.qsize(): try: # Get a value (email progress) from the queue progress = self.queue.get(0) # Update the progress bar here. except Queue.Empty: pass class ThreadedClient: # Launches the Gui and does the sending email task def __init__(self, master): self.master = master self.queue = Queue.Queue() # Set up the Gui, refer to code recipe self.gui = GuiPart(master, self.queue, ...) # Set up asynch thread (set flag to tell us we're running) self.running = 1 self.email_thread = threading.Thread(target = self.send_emails) self.email_thread.start() # Start checking the queue self.periodicCall() def periodicCall(self): # Checks contents of queue self.gui.processIncoming() # Wait X milliseconds, call this again... (see code recipe) def send_emails(self): # AKA "worker thread" while (self.running): # Send an email # Calculate the %age of email progress # Put this value in the queue! self.queue.put(value) # Eventually run out of emails to send. def endApplication(self): self.running = 0 root = Tkinter.Tk() client = ThreadedClient(root) root.mainloop() 

Intenta hacerlo así:

 progress = ttk.Progressbar(bottommenuframe, orient=HORIZONTAL, length=100, maximum=(NUMBEROFEMAILS), mode='determinate') progress.pack(side=RIGHT) def emailing(): progress.start() ##send 1 email progress.step(1) if all emails sent: progress.stop() root.after(0, emailing) 

Eso debería funcionar para ti. Espero eso ayude 🙂

Desde entonces he revisado este problema en una actualización de mi aplicación. He convertido esto en un proyecto jython usando Swing para la interfaz de usuario.

Sin embargo, me di cuenta de que usar el patrón de observador era la solución más simple para mi problema. Tener subprocesos simultáneos no era un requisito para mi proyecto y simplemente quería dar una visión aproximada del progreso. El patrón de Observer se adaptó a mis necesidades, y la implementación de Java del patrón de Observer fue especialmente útil.