翼度科技»论坛 编程开发 python 查看内容

python+Tkinter+多线程的实例

5

主题

5

帖子

15

积分

新手上路

Rank: 1

积分
15
python+Tkinter+多线程

界面和多线程一向是编程里比较难的地方,常见的做法一般是界面一个线程,后台新开一个工作线程,这两个线程进行通信,这样可以让界面不至于为响应。
在python中可以利用队列完成整体的架构设计。
直接给大家看代码吧,一个简单实例,非常好的例子。
  1. import Tkinter,time,threading,random,Queue
  2. class GuiPart():
  3.     def __init__(self,master,queue,endCommand):
  4.         self.queue=queue
  5.         Tkinter.Button(master,text='Done',command=endCommand).pack()
  6.     def processIncoming(self):
  7.         while self.queue.qsize():
  8.             try:
  9.                 msg=self.queue.get(0)
  10.                 print msg
  11.             except Queue.Empty:
  12.                 pass
  13. class ThreadedClient():
  14.     def __init__(self,master):
  15.         self.master=master
  16.         self.queue=Queue.Queue()
  17.         self.gui=GuiPart(master,self.queue,self.endApplication)
  18.         self.running=True
  19.         self.thread1=threading.Thread(target=self.workerThread1)
  20.         self.thread1.start()
  21.         self.periodicCall()
  22.     def periodicCall(self):
  23.         self.master.after(200,self.periodicCall)
  24.         self.gui.processIncoming()
  25.         if not self.running:
  26.             self.master.destroy()
  27.     def workerThread1(self):
  28.         #self.ott=Tkinter.Tk()
  29.         #self.ott.mainloop()
  30.         while self.running:
  31.             time.sleep(rand.random()*1.5)
  32.             msg=rand.random()
  33.             self.queue.put(msg)
  34.     def endApplication(self):
  35.         self.running=False
  36. rand=random.Random()
  37. root=Tkinter.Tk()
  38. client=ThreadedClient(root)
  39. root.mainloop()
复制代码
tkinter与多线程问题

长时间执行后台任务,UI会处于无响应状态。在子线程里更新UI状态,听说是不允许的。在哪个线程里调用了tk.mainloop(),就只能在哪个线程里更新UI。
下例演示了如何更新。
  1. import Tkinter as tk
  2. from ttk import *
  3. import time
  4. import Queue, threading
  5. class MainWindow:
  6.     def __init__(self):
  7.         self.root = tk.Tk()
  8.         self.root.title('Demo')
  9.     def show(self):
  10.         self.progress = tk.IntVar()
  11.         self.progress_max = 100
  12.         self.progressbar = Progressbar(self.root, mode='determinate', orient=tk.HORIZONTAL, variable=self.progress, maximum=self.progress_max)
  13.         self.progressbar.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
  14.         self.progress.set(0)
  15.         btn = tk.Button(self.root, text='start', command=self.start)
  16.         btn.pack(fill=tk.BOTH, expand=True, padx=15, pady=5)
  17.         self.btn = btn
  18.         self.root.mainloop()
  19.     def start(self):
  20.         self.progress.set(0)
  21.         self.btn.config(state=tk.DISABLED)
  22.         self.thread_queue = Queue.Queue() # used to communicate between main thread (UI) and worker thread
  23.         new_thread = threading.Thread(target=self.run_loop, kwargs={'param1':100, 'param2':20})
  24.         new_thread.start()
  25.         # schedule a time-task to check UI
  26.         # it's in main thread, because it's called by self.root
  27.         self.root.after(100, self.listen_for_result)
  28.     def run_loop(self, param1, param2):
  29.         progress = 0
  30.         for entry in range(self.progress_max):
  31.             time.sleep(0.1)
  32.             progress = progress + 1
  33.             self.thread_queue.put(progress)
  34.     def listen_for_result(self):
  35.         '''
  36.         Check if there is something in the queue.
  37.         Must be invoked by self.root to be sure it's running in main thread
  38.         '''
  39.         try:
  40.             progress = self.thread_queue.get(False)
  41.             self.progress.set(progress)
  42.         except Queue.Empty: # must exist to avoid trace-back
  43.             pass
  44.         finally:
  45.             if self.progress.get() < self.progressbar['maximum']:
  46.                 self.root.after(100, self.listen_for_result)
  47.             else:
  48.                 self.btn.config(state=tk.NORMAL)
  49. if __name__ == '__main__':
  50.     win = MainWindow()
  51.     win.show()
复制代码
一个进度条。设定最大进度为100。在子线程里每隔0.1秒更新一格。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

来源:https://www.jb51.net/article/283791.htm
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具