wxPython中的PostEvent使用哪个EvtHandler



这个问题解决了使用wxPython发布事件所需的EvtHandler的非常具体的问题。

的背景

我使用Python 2.7。在下面的例子中,我有两种类型的事件:

  1. StartMeausuringEventwx.Panel派生对象(DisplayPanel)中触发,因此我使用self.GetEventHandler(),这是有效的,即使绑定在父对象中。
  2. NewResultEvent是从threading.Thread派生对象(MeasurementThread)触发的,它没有事件处理程序,因此我被迫发送一个事件处理程序,我选择了wx.Frame派生对象(MeasurementFrame)的事件处理程序,因为这也是最终"捕获"事件的对象。

为什么第一个工作,因为对象?更一般地说,事件处理程序和"捕获"事件的对象之间的连接必须有多紧密?

代码范例
import wx
import time
import threading
import numpy as np
import wx.lib.newevent
# Create two new event types
StartMeasuringEvent, EVT_START_MEASURING = wx.lib.newevent.NewCommandEvent()
NewResultEvent,      EVT_NEW_RESULT      = wx.lib.newevent.NewEvent()

class MeasurementFrame(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, parent, title="Lets measure!", size=(300, 300))
        # Layout
        self.view = DisplayPanel(self)
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        sizer.Add(self.view, 1, wx.ALIGN_CENTER)
        self.SetSizer(sizer)
        self.SetMinSize((300, 300))
        self.CreateStatusBar()
        # Create a new measuring device object to embody a physical measuring device
        self.device = MeasuringDevice(self.GetEventHandler(), amplification=10)
        # Bind events to the proper handlers
        self.Bind(EVT_START_MEASURING, self.OnStartMeasurement)
        self.Bind(EVT_NEW_RESULT, self.OnNewResult)
    def OnStartMeasurement(self, evt):
        self.view.SetStatus("Measuring")
        self.device.start_measurement()
    def OnNewResult(self, evt):
        self.view.SetStatus("New Result!")
        print evt.result_data

class DisplayPanel(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        # Attributes
        self._result_display = wx.StaticText(self, label="0")
        self._result_display.SetFont(wx.Font(16, wx.MODERN, wx.NORMAL, wx.NORMAL))
        self._status_display = wx.StaticText(self, label="Ready!")
        self._status_display.SetFont(wx.Font(8, wx.MODERN, wx.NORMAL, wx.NORMAL))
        # Layout
        sizer = wx.BoxSizer(wx.VERTICAL)
        button1 = wx.Button(self, wx.NewId(), "Increment Counter")
        # button2 = wx.Button(self, wx.NewId(), "Decrease Counter")
        sizer.AddMany([(button1, 0, wx.ALIGN_CENTER),
                       # (button2, 0, wx.ALIGN_CENTER),
                       ((15, 15), 0),
                       (self._result_display, 0, wx.ALIGN_CENTER),
                       (self._status_display, 0, wx.ALIGN_LEFT)])
        self.SetSizer(sizer)
        # Event Handlers
        button1.Bind(wx.EVT_BUTTON, self.OnButton)
    def OnButton(self, evt):
        """ Send an event ... but to where? """
        wx.PostEvent(self.GetEventHandler(), StartMeasuringEvent(self.GetId()))
    def SetStatus(self, status=""):
        """ Set status text in the window"""
        self._status_display.SetLabel(status)

class MeasuringDevice:
    def __init__(self, event_handler, amplification=10):
        self.amplification = amplification
        self.event_handler = event_handler # The object to which all event are sent
    def start_measurement(self, repetitions=1):
        """ Start a thread that takes care of obtaining a measurement """
        for n in range(repetitions):
            worker = MeasurementThread(self.event_handler, self.amplification)
            worker.start()

class MeasurementThread(threading.Thread):
    def __init__(self, event_handler, amplification):
        threading.Thread.__init__(self)
        self.event_handler = event_handler
        self.amplification = amplification
    def run(self):
        print("Beginning simulated measurement")
        time.sleep(1) # My simulated calculation time
        result = np.random.randn()*self.amplification
        evt = NewResultEvent(result_data=result)
        wx.PostEvent(self.event_handler, evt)
        print("Simulated Measurement done!")

if __name__ == '__main__':
    my_app = wx.App(False)
    my_frame = MeasurementFrame(None)
    my_frame.Show()
    my_app.MainLoop()

第一个是有效的,因为命令事件自动沿包含层次结构(也称为窗口父/子连接)向上传播,直到找到匹配的绑定,或者直到它到达顶级父窗口(如框架或对话框)。请参阅http://wiki.wxpython.org/self.Bind%20vs.%20self.button.Bind和http://wxpython.org/OSCON2006/wxPython-intro-OSCON2006.pdf,从幻灯片53开始了解更多说明。

在寻找匹配的事件绑定时,事件处理器将搜索一个特定的路径。简而言之:如上所述,直接或间接从wx.CommandEvent派生的事件类型将继续在父窗口中搜索,直到找到匹配,对于其他类型的事件,它将只在事件发送到的窗口中查找绑定,而不会传播到父窗口。如果处理程序调用event.Skip(),那么当处理程序返回事件处理程序时,处理程序将继续寻找另一个匹配的处理程序(对于非命令事件,仍然限于同一窗口)。还有很多要比这更多,(参见上面链接的PDF中的幻灯片52)但是如果你了解了这些,那么它将足以应付你可能遇到的几乎所有事件绑定/处理情况。

顺便说一句,wx.Window类派生自wx.EvtHandler,所以除非你做了PushEventHandler之类的事情,否则window.GetEventHandler()将返回窗口本身。因此,除非您需要推送新的事件处理程序实例(大多数Python程序不需要,它在c++中更常用),否则您可以通过使用window而不是window.GetEventHandler()来节省一些输入。

相关内容

  • 没有找到相关文章

最新更新