GUI的操作必須發生在主線程或應用程序的主循環所處的地方中。
而在wxpython中使用了wxPython的全局函數wx.CallAfter(),該函數是傳遞消息給你的主線程的最容易的方法。
wx.CallAfter()使得主線程在當前的事件處理完成后,可以對一個不同的線程調用一個函數。
傳遞給wx.CallAfter()的函數對象總是在主線程中被執行。
下面是示例程序:
#-*- encoding:UTF-8 -*- import wx import threading import random class WorkerThread(threading.Thread): ''' This just simulates some long-running task that periodically sends a message to the GUI thread. 561 / 565 ''' def __init__(self,threadNum,window): threading.Thread.__init__(self) self.threadNum = threadNum self.window = window self.timeToQuit = threading.Event() self.timeToQuit.clear() self.messageCount = random.randint(10,20) self.messageDelay = 0.1 + 2.0*random.random() # 運行一個線程 def run(self): msg = "Thread %d iterating %d times with a delay of %1.4f\n"% (self.threadNum, self.messageCount,self.messageDelay) wx.CallAfter(self.window.LogMessage,msg) for i in range(1,self.messageCount+1): self.timeToQuit.wait(self.messageDelay) if self.timeToQuit.isSet():#判斷是否設置了標志位 break msg = "Message %d from thread %d\n" %(i,self.threadNum) wx.CallAfter(self.window.LogMessage,msg) else: wx.CallAfter(self.window.ThreadFinished,self) #暫停所有線程 def stop(self): self.timeToQuit.set() class MyFrame(wx.Frame): def __init__(self): wx.Frame.__init__(self,None,title="Multi-threaded GUI") self.threads=[] self.count=0 panel=wx.Panel(self) startBtn=wx.Button(panel,-1,"Start a thread") stopBtn=wx.Button(panel,-1,"Stop all threads") self.tc=wx.StaticText(panel,-1,"Worker Threads: 00") self.log=wx.TextCtrl(panel,-1,"",style=wx.TE_RICH|wx.TE_MULTILINE) inner=wx.BoxSizer(wx.HORIZONTAL) inner.Add(startBtn,0,wx.RIGHT,15) inner.Add(stopBtn,0,wx.RIGHT,15) inner.Add(self.tc,0,wx.ALIGN_CENTER_VERTICAL) main=wx.BoxSizer(wx.VERTICAL) main.Add(inner,0,wx.ALL,5) main.Add(self.log,1,wx.EXPAND|wx.ALL,5) panel.SetSizer(main) self.Bind(wx.EVT_BUTTON,self.OnStartButton,startBtn) self.Bind(wx.EVT_BUTTON,self.OnStopButton,stopBtn) self.Bind(wx.EVT_CLOSE,self.OnCloseWindow) self.UpdateCount() def OnStartButton(self,evt): self.count+=1 thread=WorkerThread(self.count,self)#創建一個線程 self.threads.append(thread) self.UpdateCount() thread.start()#啟動線程 def OnStopButton(self,evt): self.StopThreads() self.UpdateCount() def OnCloseWindow(self,evt): self.StopThreads() self.Destroy() def StopThreads(self):#從池中刪除線程 while self.threads: thread=self.threads[0] thread.stop() self.threads.remove(thread) def UpdateCount(self): self.tc.SetLabel("Worker Threads: %d"%len(self.threads)) def LogMessage(self,msg):#注冊一個消息 self.log.AppendText(msg) def ThreadFinished(self,thread):#刪除線程 self.threads.remove(thread) self.UpdateCount() app=wx.App() frm=MyFrame() frm.Show() app.MainLoop()
上面這個例子使用了Python的threading模塊。上面的代碼使用wx.CallAfter(func,*args)傳遞方法給主線程。這將發送一個事件給主線程,之后,事件以標准的方式被處理,並觸發對func(*args)的調用。因些,在這種情況中,線程在它的生命周期期間調用LogMessage(),並在線程結束前調用ThreadFinished()。