2011-11-29 26 views
2

例如:單純使用線程更新GUI還不夠嗎?

class DemoFrame(wx.Frame): 

    def __init__(self): 
     Initializing 
     ... 
     self.TextA = wx.StaticText(MainPanel, id = -1, label = "TextAOrWhatever") 
     self.TextB = wx.StaticText(MainPanel, id = -1, label = "TextBOrWhatever") 
     ... 

    def StaticTextUpdating(self, ObjectName, Message): 
     ObjectName.SetLabel(Message) 

    def WorkerA(self): 
     while True: 
      Work on something 

      UpdatingThread = threading.Thread(target = self.StaticTextUpdating, args = (self.TextA, "Something for TextA",)) 
      UpdatingThread.start() 

      time.sleep(randomSecs) 

    def WorkerB(self): 
     while True: 
      Work on something 

      UpdatingThread = threading.Thread(target = self.StaticTextUpdating, args = (self.TextB, "Something for TextB",)) 
      UpdatingThread.start() 

      time.sleep(randomSecs) 

    ... 

    def StartWorking(self): 
     Spawn WorkerA thread 
     Spawn WorkerB thread 
     ... 

正如你所看到的,我總是更新新主題StaticText,我100%肯定在任何特定的時間點,只有一個線程更新的特定對象,但問題是,每隔一段時間運行一段時間後,一些物體就會消失。這是爲什麼發生?這是否意味着GUI更新不是線程安全的?也許只有一個對象可以在某個時間點更新?

補充:

OK,wx.CallAfter應該是上面的代碼一個很好的解決方案。但是我還有一個問題,如果一個按鈕事件和SetLabel同時發生了什麼?這樣的事情會不會引起麻煩,儘管我沒有看到任何問題?

+0

wx.CallAfter在UI線程中序列化方法調用。由於事件是在UI線程中分派的,因此如果使用wx.CallAfter,它們不會「同時」發生。如果你不是,那麼在一些線程中發生的事情可能會引發一堆問題。例如,想想MS-Windows上的DC重用。或者2個線程試圖同時寫入Linux上的相同套接字(連接到X服務器)... – fraca7

+0

@ fraca7:非常感謝! – Shane

回答

4

大多數wx方法不是線程安全的。如果要從另一個線程調用wx方法,請使用wx.CallAfter;更換

ObjectName.SetLabel(Message) 

有:

wx.CallAfter(ObjectName.SetLabel, Message) 

編輯:一些背景信息

在WX(以及大多數其他UI平臺)的所有UI更新可以在被稱爲主單個線程執行線程(或UI線程)。這是爲了通過避免線程同步的性能影響來加快UI的工作。

但是這樣做的缺點是如果我們編寫代碼來更新不同線程的UI,結果是不確定的。有時它可能有用,有時可能會崩潰,有時可能會發生其他一些事情。所以我們應該總是去UI線程做UI更新。所以我們使用CallAfter函數在UI線程中執行UI更新函數。

UI thread in java

UI thread in C#

+1

如果有一些背景信息,爲什麼需要這樣做呢? 「WX方法/函數不是線程安全的」不是完整的答案。 –