wxPython 中的 PostEvent 使用哪个 EvtHandler
Which EvtHandler to use for PostEvent in wxPython
这个问题解决了使用 wxPython.
post en 事件所需的 EvtHandler
的非常具体的问题
背景
我正在使用 Python 2.7。
在下面的示例中,我有两种事件:
StartMeausuringEvent
在 wx.Panel
派生对象 (DisplayPanel
) 中触发,因此我使用 self.GetEventHandler()
,这有效,即使绑定在父对象中.
NewResultEvent
是由 threading.Thread
派生对象 (MeasurementThread
) 触发的,它没有事件处理程序,因此我不得不发送一个事件处理程序,我选择 wx.Frame
派生对象 (MeasurementFrame
) 的事件处理程序,因为这也是最终 "cathes" 事件的对象。
问题
为什么第一个有效,因为对象?更一般地说,事件处理程序和事件必须 "catches" 的对象之间的联系有多紧密?
代码示例
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()
第一个有效,因为命令事件自动向上传播包含层次结构(a.k.a window parent/child 连接)直到找到匹配的绑定或直到它到达顶部-level parent window 像框架或对话框。有关详细说明,请参阅 http://wiki.wxpython.org/self.Bind%20vs.%20self.button.Bind and also http://wxpython.org/OSCON2006/wxPython-intro-OSCON2006.pdf 从幻灯片 53 开始。
事件处理器在查找匹配的事件绑定时将搜索特定路径。简而言之:如上所述,直接或间接派生自 wx.CommandEvent
的事件类型将继续通过父级向上搜索,直到找到匹配项,而对于其他类型的事件,它只会在 [= 中查找绑定34=] 事件被发送到并且不会传播到父 windows。如果处理程序调用 event.Skip()
,那么当处理程序 return 时,事件处理器将继续寻找另一个匹配的处理程序(对于非命令事件仍然限于相同的 window。)有 比这更多,(请参阅上面链接的 PDF 中的幻灯片 52)但是如果您了解这么多,那么几乎所有事件都足够了 binding/handling 您的情况很可能会遇到。
顺便说一句,wx.Window
class 派生自 wx.EvtHandler
所以除非你做了类似 PushEventHandler
的事情,否则 window.GetEventHandler()
将 return window 本身。所以除非你需要推送新的事件处理程序实例(大多数 Python 程序不需要,它在 C++ 中更常用)那么你可以通过使用 window
而不是 [=15= 来节省一些输入].
这个问题解决了使用 wxPython.
post en 事件所需的EvtHandler
的非常具体的问题
背景
我正在使用 Python 2.7。 在下面的示例中,我有两种事件:
StartMeausuringEvent
在wx.Panel
派生对象 (DisplayPanel
) 中触发,因此我使用self.GetEventHandler()
,这有效,即使绑定在父对象中.NewResultEvent
是由threading.Thread
派生对象 (MeasurementThread
) 触发的,它没有事件处理程序,因此我不得不发送一个事件处理程序,我选择wx.Frame
派生对象 (MeasurementFrame
) 的事件处理程序,因为这也是最终 "cathes" 事件的对象。
问题
为什么第一个有效,因为对象?更一般地说,事件处理程序和事件必须 "catches" 的对象之间的联系有多紧密?
代码示例
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()
第一个有效,因为命令事件自动向上传播包含层次结构(a.k.a window parent/child 连接)直到找到匹配的绑定或直到它到达顶部-level parent window 像框架或对话框。有关详细说明,请参阅 http://wiki.wxpython.org/self.Bind%20vs.%20self.button.Bind and also http://wxpython.org/OSCON2006/wxPython-intro-OSCON2006.pdf 从幻灯片 53 开始。
事件处理器在查找匹配的事件绑定时将搜索特定路径。简而言之:如上所述,直接或间接派生自 wx.CommandEvent
的事件类型将继续通过父级向上搜索,直到找到匹配项,而对于其他类型的事件,它只会在 [= 中查找绑定34=] 事件被发送到并且不会传播到父 windows。如果处理程序调用 event.Skip()
,那么当处理程序 return 时,事件处理器将继续寻找另一个匹配的处理程序(对于非命令事件仍然限于相同的 window。)有 比这更多,(请参阅上面链接的 PDF 中的幻灯片 52)但是如果您了解这么多,那么几乎所有事件都足够了 binding/handling 您的情况很可能会遇到。
顺便说一句,wx.Window
class 派生自 wx.EvtHandler
所以除非你做了类似 PushEventHandler
的事情,否则 window.GetEventHandler()
将 return window 本身。所以除非你需要推送新的事件处理程序实例(大多数 Python 程序不需要,它在 C++ 中更常用)那么你可以通过使用 window
而不是 [=15= 来节省一些输入].