如果在事件处理程序中调用,wx.PostEvent不会触发事件?

时间:2017-04-10 07:33:12

标签: wxpython wxwidgets

我正在Ubuntu 14.04上尝试下面发布的代码为combotest.py,MATE桌面,python 2.7,python-wxgtk2.8 2.8.12.1;应用程序是这样的:

combotest

当我点击组合框并直接更改它时,会触发相应的事件处理程序OnUpdateComboBox,并在stdout上打印出来:

OnUpdateComboBox <wx._controls.ComboBox; proxy of <Swig Object of type 'wxComboBox *' at 0x909caf0> > MyComboBox

我知道:

http://wxpython-users.1045709.n5.nabble.com/SetValue-on-spinctrl-doesn-t-send-update-event-td2289628.html

  

一般政策是用户对控件值的更改   生成事件和以编程方式进行的更改。所以你应该   计划在SetValue上不发送事件,

当点击按钮时,我正在尝试更改选项 - 并在组合框中触发相应的处理程序。正如WxPython - trigger checkbox event while setting its value in the code中所建议的那样,我试图调用wx.PostEvent()来强制调用组合框事件处理程序,一旦按钮代码以编程方式更改了它的选择。

当我点击按钮时,我可以看到它的处理程序BtnClickHandler被调用,并且正如预期的那样,它将组合框选择更改为新项目 - 但是,调用wx.PostEvent(),无论它是否是独立或wx.CallAfter(),只是永远不会调用OnUpdateComboBox

那么,当从按钮事件处理程序以编程方式更改其选择时,如何调用组合框事件处理程序?或者这是一个错误?

编辑:结果我可以直接调用该函数,所以在BtnClickHandler我可以这样做:

self.OnUpdateComboBox(oevt)

...然后处理程序将被调用 - 但有些事情对此感觉不正确......

此外,即使组合框中有5个项目,self.combo_box.GetLastPosition()返回2的任何想法都会出现?!

combotest.py

import wxversion
wxversion.select("2.8")
import wx, wx.html
import sys

class Frame(wx.Frame):
  def __init__(self, *args, **kwds):
    kwds["style"] = wx.DEFAULT_FRAME_STYLE
    wx.Frame.__init__(self, *args, **kwds)

    self.label = wx.StaticText(self, wx.ID_ANY, "Click the button to change combobox below: ")
    self.bt_main = wx.Button(self, label="Click ME")
    self.bt_main.Bind(wx.EVT_BUTTON, self.BtnClickHandler)
    self.combo_box = wx.ComboBox(self, wx.ID_ANY, choices=["AAA", "BBB", "CCC", "DDD", "EEE"], style=wx.CB_DROPDOWN | wx.CB_READONLY, name="MyComboBox")
    self.combo_box.SetSelection(0) # this does not call event
    wx.PostEvent(self.combo_box, wx.CommandEvent(wx.EVT_COMBOBOX.typeId)) #neither does this
    self.Bind(wx.EVT_COMBOBOX, self.OnUpdateComboBox, self.combo_box)

    sizer_vmain_app = wx.BoxSizer(wx.VERTICAL)
    sizer_vmain_app.Add(self.label, proportion=0, flag=wx.EXPAND, border=0)
    sizer_vmain_app.Add(self.bt_main, proportion=0, flag=0, border=0)
    sizer_vmain_app.Add(self.combo_box, proportion=0, flag=0, border=0)

    self.SetSizer(sizer_vmain_app)
    self.Layout()

  def OnUpdateComboBox(self, event):
    widget = event.GetEventObject()
    print("OnUpdateComboBox " + repr(widget) + " " + widget.GetName())

  def BtnClickHandler(self, event):
    print("BtnClickHandler " + repr(self.combo_box.GetLastPosition()))
    newsel = (self.combo_box.GetSelection() + 1) % (self.combo_box.GetLastPosition()+1) # GetLastPosition is 2, even with 5 items in box?!
    self.combo_box.SetSelection(newsel) # this does not call event
    oevt = wx.CommandEvent(commandType=wx.EVT_COMBOBOX.typeId)
    oevt.SetEventObject(self.combo_box)
    wx.PostEvent(self.combo_box, oevt) # does nothing
    wx.CallAfter(wx.PostEvent, self.combo_box, oevt) # does nothing

if __name__ == "__main__":
  app = wx.PySimpleApp(0)
  wx.InitAllImageHandlers()
  app_frame = Frame(None, wx.ID_ANY, "")
  app.SetTopWindow(app_frame)
  app_frame.Show()
  app.MainLoop()

2 个答案:

答案 0 :(得分:0)

请不要直接调用事件处理函数 - 尤其是这样。 更好的解决方案是创建一个函数,该函数将执行组合框中的值更改时需要执行的任何操作,并从两个处理程序中调用此函数。

另外,如果知道wx-3.0 / 3.1中的所有内容是否都能正常工作,那就太好了。

答案 1 :(得分:0)

好的我找到了解决方案。直接绑定到组合框而不是框架。这是一个工作示例(wx phoenix 3.03.xyz dev ....)

class Frame(wx.Frame):
    def __init__(self, *args, **kwds):
        kwds["style"] = wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)

        self.label = wx.StaticText(self, wx.ID_ANY, "Click the button to change combobox below: ")
        self.bt_main = wx.Button(self, label="Click ME")
        self.bt_main.Bind(wx.EVT_BUTTON, self.BtnClickHandler)
        self.combo_box = wx.ComboBox(self, wx.ID_ANY, choices=["AAA", "BBB", "CCC", "DDD", "EEE"],
                                     style=wx.CB_DROPDOWN | wx.CB_READONLY, name="MyComboBox")
        # self.Bind(wx.EVT_COMBOBOX, self.OnUpdateComboBox, self.combo_box)
        # bind directly to the widget
        self.combo_box.Bind(wx.EVT_COMBOBOX, self.OnUpdateComboBox)

        self.combo_box.SetSelection(0) 
        combo_event = wx.CommandEvent(wx.EVT_COMBOBOX.typeId)
        combo_event.SetEventObject(self.combo_box)
        wx.PostEvent(self.combo_box, combo_event)


        sizer_vmain_app = wx.BoxSizer(wx.VERTICAL)
        sizer_vmain_app.Add(self.label, proportion=0, flag=wx.EXPAND, border=0)
        sizer_vmain_app.Add(self.bt_main, proportion=0, flag=0, border=0)
        sizer_vmain_app.Add(self.combo_box, proportion=0, flag=0, border=0)

        self.SetSizer(sizer_vmain_app)
        self.Layout()

    def OnUpdateComboBox(self, event):
        widget = event.GetEventObject()
        print("OnUpdateComboBox " + repr(widget) + " " + widget.GetName())

    def BtnClickHandler(self, event):
        print("BtnClickHandler " + repr(self.combo_box.GetLastPosition()))
        newsel = (self.combo_box.GetSelection() + 1) % (
        self.combo_box.GetLastPosition() + 1)  # GetLastPosition is 2, even with 5 items in box?!
        self.combo_box.SetSelection(newsel)  # this does not call event
        oevt = wx.CommandEvent(commandType=wx.EVT_COMBOBOX.typeId)
        oevt.SetEventObject(self.combo_box)
        wx.PostEvent(self.combo_box, oevt)  # does nothing
        wx.CallAfter(wx.PostEvent, self.combo_box, oevt)  # does nothing


if __name__ == "__main__":
    app = wx.PySimpleApp(0)
    wx.InitAllImageHandlers()
    app_frame = Frame(None, wx.ID_ANY, "")
    app.SetTopWindow(app_frame)
    app_frame.Show()
    app.MainLoop()

旁注

self.combox_box.GetLastPosition()指的是编辑时的光标位置,而不是最后一个选择