2010-02-26 14 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

相关问题