在wxPython

时间:2015-05-29 09:40:33

标签: python python-2.7 wxpython python-multithreading

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

背景

我正在使用Python 2.7。 在下面的示例中,我有两种事件:

  1. StartMeausuringEventwx.Panel派生对象(DisplayPanel)内触发,因此我使用self.GetEventHandler(),即使绑定位于父对象中,也可以使用NewResultEvent。 / LI>
  2. 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() )的事件处理程序,因为这也是最终“碰撞”事件的对象。
  3. 问题

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

    代码示例

    /**
     * Sends ArDrone the gaz value. Makes drone to move up or down
     *
     * @param value - value between -1 and 1.
     */
    public void setGaz(final float value) {
        droneProxy.setControlValue(CONTROL_SET_GAZ, value);
    }
    
    /**
     * Sends ArDrone the Roll value. Makes drone to move left or right
     *
     * @param value - value between -1 and 1.
     */
    public void setRoll(final float value) {
        droneProxy.setControlValue(CONTROL_SET_ROLL, value);
    }
    
    /**
     * Sends ArDrone the Pitch value. Makes drone to move forward or backward
     *
     * @param value - value between -1 and 1.
     */
    public void setPitch(final float value) {
        droneProxy.setControlValue(CONTROL_SET_PITCH, value);
    }
    
    /**
     * Sends ArDrone the gaz value. Makes drone to turn left or right
     *
     * @param value - value between -1 and 1.
     */
    public void setYaw(final float value) {
        droneProxy.setControlValue(CONTROL_SET_YAW, value);
    }
    

1 个答案:

答案 0 :(得分:1)

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

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

顺便说一句,event.Skip()类派生自wx.Window,所以除非你做过像wx.EvtHandler这样的事情,否则PushEventHandler会返回窗口本身。因此,除非你需要推送新的事件处理程序实例(大多数Python程序没有,它在C ++中更常用),然后你可以通过使用window.GetEventHandler()代替window来保存一些输入。