2010-02-26 52 views
2

我想學習如何運行一個線程關閉主GUI應用程序來做我的串口發送/接收,同時保持我的GUI活着。我最好的Google搜索嘗試將我帶到了wxpython wiki:http://wiki.wxpython.org/LongRunningTasks,它提供了幾個示例。我決定學習第一個例子,涉及在選擇特定按鈕時啓動工作線程。wxPython:線程的GUI - >使用自定義的事件處理程序

我無法理解的自定義事件定義:

def EVT_RESULT(win, func): 
    """Define Result Event.""" 
    win.Connect(-1, -1, EVT_RESULT_ID, func) 

class ResultEvent(wx.PyEvent): 
    """Simple event to carry arbitrary result data.""" 
    def __init__(self, data): 
     """Init Result Event.""" 
     wx.PyEvent.__init__(self) 
     self.SetEventType(EVT_RESULT_ID) 
     self.data = data 

主要是

def EVT_RESULT(win, func): 
    """Define Result Event.""" 
    win.Connect(-1, -1, EVT_RESULT_ID, func) 

我覺得EVT_RESULT被放置在類的外部,以使其呼叫能夠通過兩類(使其成爲全球?)

並且..主GUI應用程序通過以下方式監視線程的進度:

# Set up event handler for any worker thread results 
EVT_RESULT(self,self.OnResult) 

我也注意到,在很多例子中,當筆者使用

from wx import * 

他們只需

EVT_SOME_NEW_EVENT(self, self.handler) 

綁定的東西,而不是

wx.Bind(EVT_SOME_NEW_EVENT, self.handler) 

哪個沒有按幫助我更快地理解它。 謝謝,

回答

2

可以定義這樣的活動:

from wx.lib.newevent import NewEvent 

ResultEvent, EVT_RESULT = NewEvent() 

你發佈這樣的事件:

wx.PostEvent(handler, ResultEvent(data=data)) 

綁定這樣的:

def OnResult(event): 
    event.data 

handler.Bind(EVT_RESULT, OnResult) 

但如果你只需要在主線程中可以使用wx.CallAfter,here是一個非主線程調用的例子。

當您不想硬編碼誰負責什麼(請參閱observer design pattern)時,自定義事件很有用。例如,假設你有一個主窗口和幾個子窗口。假設在主窗口發生某種變化時需要刷新一些子窗口。在這種情況下,主窗口可以直接刷新這些子窗口,但更優雅的方法是定義一個自定義事件並讓主窗口將其發佈給自己(而不必打擾誰需要對其進行響應)。然後,那些需要對這個事件作出反應的孩子可以通過綁定它來完成它自己(如果有多個孩子,他們呼叫event.Skip()以便所有綁定方法被調用是很重要的)。

+0

感謝您的答案,我將在我工作時提及它。 – PPTim 2010-03-01 21:26:36

4

這是定義自定義事件的舊風格。有關更多信息,請參閱the migration guide

從遷移指南摘自:

如果你創建自己的自定義事件 類型和EVT_ *功能,您 希望能夠與 綁定方法使用它們上面,那麼你應該 將您的EVT_ *更改爲wx.PyEventBinder的實例,而不是 函數。例如,如果您使用 有這樣的事情:

myCustomEventType = wxNewEventType() 
def EVT_MY_CUSTOM_EVENT(win, id, func): 
    win.Connect(id, -1, myCustomEventType, func) 

更改它像這樣:

myCustomEventType = wx.NewEventType() 
EVT_MY_CUSTOM_EVENT = wx.PyEventBinder(myCustomEventType, 1) 

Here is another post,我與一對夫婦做的正是你是什麼示例程序的製作尋找。

+0

謝謝,我會看看那 – PPTim 2010-03-01 21:25:04

+0

你做好了你的工作,你歸檔了那部分頁面。它似乎是動態和非版本化的,所以文本不再存在!相關閱讀:https://wiki.wxpython.org/CustomEventClasses – Pod 2016-11-03 15:52:26

0

您可能想要使用Python線程和隊列,而不是自定義事件。我有一個wxPython程序(OpenSTV),它會加載導致gui在加載期間凍結的大文件。爲了防止凍結,我派遣一個線程來加載文件並使用一個隊列在GUI和線程之間進行通信(例如,向GUI傳遞一個例外)。

def loadBallots(self): 
    self.dirtyBallots = Ballots() 
    self.dirtyBallots.exceptionQueue = Queue(1) 
    loadThread = Thread(target=self.dirtyBallots.loadUnknown, args=(self.filename,)) 
    loadThread.start() 

    # Display a progress dialog 
    dlg = wx.ProgressDialog(\ 
     "Loading ballots", 
     "Loading ballots from %s\nNumber of ballots: %d" % 
     (os.path.basename(self.filename), self.dirtyBallots.numBallots), 
     parent=self.frame, style = wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME 
    ) 
    while loadThread.isAlive(): 
     sleep(0.1) 
     dlg.Pulse("Loading ballots from %s\nNumber of ballots: %d" % 
       (os.path.basename(self.filename), self.dirtyBallots.numBallots)) 
    dlg.Destroy() 

if not self.dirtyBallots.exceptionQueue.empty(): 
    raise RuntimeError(self.dirtyBallots.exceptionQueue.get()) 
+1

我想隊列是多線程的標準方式;但如果我需要的只是一個簡單的「完成」信號,是否可以安全通過?我沒有使用過多的隊列;我需要爲每個方向創建一個,並且基本上有接收端定期輪詢隊列? – PPTim 2010-03-02 17:09:07

+0

您不需要一個隊列來確定線程何時完成。您可以使用上例中使用的isAlive()。你確實需要一個在每個方向進行通信的隊列,你可以在runElection(http://code.google.com/p/stv/source/browse/trunk/openstv/OpenSTV.py)中看到一個例子。 )。 – 2010-03-03 16:07:55

相關問題