发送邮件时TTK进度条被阻塞
我正在用Python和tkinter写一个应用程序。在这个应用里,我想批量发送邮件,同时显示一个进度条来让用户知道进度。我可以创建进度条并启动它,但在发送邮件的时候,进度条就不动了(如果我在发送邮件之前就启动了进度条,我想在发送邮件前启动它,但这样做时进度条就停在那里,什么都不动)。
startProgressBar()
sendEmails()
stopProgressBar()
我尝试把发送邮件的部分放到一个单独的线程里,但似乎没有成功。我使用的是高级的线程模块。有没有什么建议?也许我对线程的理解有问题。我用smtplib来发送邮件。
3 个回答
0
我最近在更新我的应用程序时又回到了这个问题上。我把它转换成了一个使用Swing作为界面的jython项目。
不过,我发现使用观察者模式是解决我问题的最简单方法。我的项目并不需要同时运行多个线程,我只是想大致显示一下进度。观察者模式完全符合我的需求,而Java中的观察者模式实现特别有帮助。
0
试试这样做:
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)
这样应该可以解决你的问题。希望对你有帮助 :)
2
这是一个老问题,但我提到的代码示例对我理解类似的概念很有帮助,所以我觉得应该分享一下。
这种类型的问题需要用到线程,这样我们才能把更新界面和实际执行任务(比如发送邮件)的工作分开。你可以看看这个来自Active State的代码示例,我相信它正好是你需要的关于线程和线程之间传递信息(通过队列)的例子。
我会强调代码示例中的重要部分。我不包括进度条的设置,而是关注整体的代码结构以及如何获取和设置队列。
import Tkinter
import threading
import Queue
class GuiPart:
def __init__(self, master, queue, endCommand):
self.queue = queue
# Do GUI set up here (i.e. 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()