2014-03-28 30 views
1

我在Windows 7操作系統上使用python v2.7和wxPython v3.0。 在下面的代碼片段中,我實現了一個發佈者訂閱機制來更新我的GUI。我正在使用wx.CallAfter()將更新發送到我的GUI主循環。wx.CallAfter()在wxPython中的無限循環中崩潰應用程序/ python

問題:爲什麼我的應用程序下方提供的代碼段崩潰。這是爲什麼發生?如何避免這種情況?

代碼:在代碼中使用的圖像可以從這裏blue.bmp & g.bmp下載。

import wx 
import time 
from wx.lib.pubsub import setupkwargs 
from wx.lib.pubsub import pub 
from threading import Thread 
import threading 
import random 

class gui(wx.Frame): 

    def __init__(self, parent, id, title): 
     wx.Frame.__init__(self, None, id, title, size=(200,200), style=wx.DEFAULT_FRAME_STYLE^wx.RESIZE_BORDER) 
     self.mainPanel = mainPanel = wx.Panel(self, -1) 
     mySizer = wx.BoxSizer(wx.VERTICAL) 
     self.myButton1 = wx.Button(mainPanel, -1, size=(30,30)) 
     mySizer.Add(self.myButton1) 
     mainPanel.SetSizer(mySizer) 
     Bimage_file = 'blue.bmp' 
     self.Blue = wx.Image(Bimage_file, wx.BITMAP_TYPE_ANY).ConvertToBitmap() 
     Gimage_file = 'g.bmp' 
     self.Green = wx.Image(Gimage_file, wx.BITMAP_TYPE_ANY).ConvertToBitmap() 
     pub.subscribe(self.updateImages, 'Update') 

    def updateImages(self, value): 
     self.myButton1.DestroyChildren() 
     if value <= 5: 
      wx.StaticBitmap(self.myButton1, -1, self.Blue, (0, 0)) 
      self.mainPanel.Layout() 
     else: 
      wx.StaticBitmap(self.myButton1, -1, self.Green, (0, 0)) 
      self.mainPanel.Layout() 
class myThread(Thread): 
    def __init__(self): 
     Thread.__init__(self) 
     self.start() 
    def run(self): 
     while True: 
      result = random.randrange(0,10) 
      wx.CallAfter(pub.sendMessage, 'Update', value=result) 
      #Uncomment the following line to avoid the crash!!! 
      #time.sleep(1) 
if __name__=='__main__': 
    app = wx.App() 
    frame = gui(parent=None, id=-1, title="Demo") 
    frame.Show() 
    myThread() 
    app.MainLoop() 

但是如果我wx.CallAfter()後添加以下行正常工作:

time.sleep(1) 

感謝您的時間!

回答

3

該問題可能是由於Windows消息隊列溢出。有關於wxWidgets錯誤跟蹤器中的這個錯誤的several tickets,其中一些事件已經修復,但可能並非全部。在任何情況下,即使我們總是避免溢出,但用這樣的事件淹沒主線程仍然是一個壞主意(因爲每個呼叫在道德上等同於事件)。在現實生活中,後臺線程會在它們之間做一些工作,所以這不太可能發生,但是如果你真的需要在這樣的玩具例子中工作,使用sleep()實際上可能是正確的。

+0

謝謝。如果這是wxPython或Windows操作系統的問題,您可以回答嗎?你認爲wx.CallLater()在這種情況下可以提供幫助,還是不會產生任何影響? –

+2

我不知道'wx.CallLater()'實現的細節,所以我不確定。好消息是我認爲崩潰實際上已經被修復了,請看[這張票](http://trac.wxwidgets.org/ticket/15951),所以你的代碼應該在wxPython 3.0.1沒有改變的情況下工作,當它發佈 - 或者如果您使用當前的3.0分支源代碼構建自己的wxPython。 –

+1

@ps VZ的答案看起來很合理。然後'wx.CallLater'不會幫助:這個函數稍後調用給定的函數,但仍然會立即返回,所以你仍然會溢出事件隊列。您不需要每秒更新GUI一百萬次;如果你想要平滑的效果,每秒幾次應該是足夠的,所以你可以使用'time.sleep(0.1)'每秒10次,或者當更新後的值改變超過一定值時才產生消息(如果發佈的價值沒有改變,肯定不會產生消息!)。 – Schollii

0

也許你的線程應該有回調回調或只是一個變量(信號量)來知道CallAfter何時執行?

將您的pub.sendMessage調用包裝在另一個函數中,例如,在發送消息後清除信號標誌 。您的線程可以在發出 CallAfter之前設置信號量,然後在發送另一個信號之前等待信號量清除。

如果您將它設置爲計數器,您將在計數器上增加計數,並在清除時減少計數,並且只允許計數增加,以限制排隊等待CallAfter的數量。