Search code examples
pythonwxpython

EVT_KILL_FOCUS event in wxPython not firing or handler is wrong


Below is a demo program (a bit long, but it is hard to make a wxPython app short) that exhibits my difficulty. The program asks for input in 2 text fields. Each text field has 2 handlers, that are supposed to trap the events EVT_TEXT (hander on_text_changed()) and EVT_KILL_FOCUS (handler on_focus_lost()).

When I type in either field, the handler on_text_changed() gets called and prints the expected message. I expect that when I tab between the two fields, or click on a field with a mouse, the handler on_focus_lost() should get called for the field that the lost the focus. But it doesn't get called. So either I have a poor grasp of what the event is for, or the way I have set up the event handler is wrong.

What am I missing here?

import wx

class DemoFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        kwds["style"] = kwds.get("style", 0) | wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.SetSize((400, 300))
        self.SetTitle("Demo")

        self.panel_1 = wx.Panel(self, wx.ID_ANY)

        sizer_1 = wx.BoxSizer(wx.HORIZONTAL)

        self.text_ctrl_1 = wx.TextCtrl(self.panel_1, wx.ID_ANY, "")
        sizer_1.Add(self.text_ctrl_1, 0, 0, 0)

        self.text_ctrl_2 = wx.TextCtrl(self.panel_1, wx.ID_ANY, "")
        sizer_1.Add(self.text_ctrl_2, 0, 0, 0)

        self.panel_1.SetSizer(sizer_1)

        self.Layout()

        self.Bind(wx.EVT_KILL_FOCUS, self.on_focus_lost, self.text_ctrl_1)
        self.Bind(wx.EVT_TEXT, self.on_text_changed, self.text_ctrl_1)
        self.Bind(wx.EVT_KILL_FOCUS, self.on_focus_lost, self.text_ctrl_2)
        self.Bind(wx.EVT_TEXT, self.on_text_changed, self.text_ctrl_2)

    def on_focus_lost(self, event):
        print("Event handler for EVT_KILL_FOCUS")
        event.Skip()

    def on_text_changed(self, event):
        print("Event handler for EVT_TEXT, value is", event.String)
        event.Skip()

class DemoApp(wx.App):
    def OnInit(self):
        self.frame = DemoFrame(None, wx.ID_ANY, "")
        self.SetTopWindow(self.frame)
        self.frame.Show()
        return True


if __name__ == "__main__":
    demo = DemoApp(0)
    demo.MainLoop()

Solution

  • Try setting the binding directly on the controls:

     self.text_ctrl_1.Bind(wx.EVT_KILL_FOCUS, self.on_focus_lost)