I'm trying the code posted below as combotest.py
on Ubuntu 14.04, MATE desktop, python 2.7, python-wxgtk2.8 2.8.12.1; the application is like this:
When I click on the combobox and change it directly, the corresponding event handler OnUpdateComboBox
fires, and I get this printed on stdout:
OnUpdateComboBox <wx._controls.ComboBox; proxy of <Swig Object of type 'wxComboBox *' at 0x909caf0> > MyComboBox
I am aware that:
the general policy is that changes to a control's value made by the user generates events and changes made programatically do not. So you should plan on SetValue not sending the event,
I'm trying to have the choice changed - and the corresponding handler fired - in the combobox, when the button is clicked. And as recommended in WxPython - trigger checkbox event while setting its value in the code, I'm therefore trying to call wx.PostEvent()
to force the call of the combobox event handler, once its selection has been programmatically changed by the button code.
When I click the button, I can see its handler BtnClickHandler
does get called, and as expected, it changes the combobox selection to a new item - however, calling wx.PostEvent()
, regardless if it is standalone or in wx.CallAfter()
, simply never calls the OnUpdateComboBox
.
So, how can I call the combobox event handler, when changing its selection programmatically from the button event handler? Or is this a bug?
EDIT: Turns out I can call the function directly, so in BtnClickHandler
I can do:
self.OnUpdateComboBox(oevt)
... and then the handler will get called - but something just doesn't feel right about this...
Also, any ideas why self.combo_box.GetLastPosition()
returns 2, even though there are 5 items in the combobox ?!
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()