Search code examples
comboboxwxpythonsetfocus

wxpython SetFocus and EVT_KILL_FOCUS combobox


I am trying to understand how EVT_KILL_FOCUS and SetFocus on a combobox works .Here is the following code:

import wx

class MainWindow(wx.Frame):

    count = 1

    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, title=title, size=(150,150), style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER ^ wx.MAXIMIZE_BOX)
        panel = wx.Panel(self, -1)

        self.Calc_Display = wx.ComboBox(panel, -1, style=wx.CB_DROPDOWN|wx.TE_PROCESS_ENTER)
        self.Calc_Display.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)

        btn = wx.Button(panel, label="Test")

        MainFrameSizer = wx.BoxSizer(wx.VERTICAL)
        MainFrameSizer.Add(self.Calc_Display, 0, wx.ALL | wx.EXPAND | wx.ALIGN_CENTER, 5)
        MainFrameSizer.Add(btn, 0, wx.ALL | wx.EXPAND | wx.ALIGN_CENTER, 5)

        panel.SetSizer(MainFrameSizer)
        panel.Fit()
        self.Show()


    def OnKillFocus(self, event):
        print ('EVT_KILL_FOCUS was called %i times' %MainWindow.count)
        MainWindow.count += 1
        # self.Calc_Display.SetFocus()
        event.Skip()


app = wx.App(False)
frame = MainWindow(None, "Test")
app.MainLoop()

If run this, you will get a print every time the combobox loses focus, which is expected. If you uncomment line 28, that's when it gets weird. The EVT_KILL_FOCUS gets called over and over. That is the behavior I am trying to understand. In the program I am writing, I want to force the combobox to maintain focus in case a condition is not satisfied. Are there any ways around this behavior?

I found this link on the issue, but I did not quite understand it: http://wiki.wxpython.org/Surviving%20with%20wxEVT%20KILL%20FOCUS%20under%20Microsoft%20Windows

Thanks for any help


Solution

  • After reading the link posted in your question, and playing around with your code, I came to the conclusion that calling SetFocus() on the combobox is apparently triggering the EVT_KILL_FOCUS in Windows. I had noticed that on running the program, it prints the statement once, although It shouldn't since the combobox is not losing focus.

    I tried two things:

    First was to move the combo box code after the button code. In this case when the program is run the Focus is on the button, and sure enough the statement is not printed!

    Here's the edit:

    btn = wx.Button(panel, label="Test")
    
    self.Calc_Display = wx.ComboBox(panel, -1, style=wx.CB_DROPDOWN|wx.TE_PROCESS_ENTER)
    self.Calc_Display.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
    

    Second was to try binding the btn to a handler which sets the focus on the combobox

    btn.Bind(wx.EVT_BUTTON, self.On_Button)
    
    def On_Button(self, event):
        self.Calc_Display.SetFocus()
    

    In this case the statement was being printed twice every time the button was being clicked. I guess this is once for when the focus is lost and once for setting back the focus. Note that the SetFocus() is still commented out in the OnKillFocus in this case.

    Back to your code: If the SetFocus is "uncomment-ed" the statement is printed many times because it keeps setting the focus which in turn triggers the event and it goes on in a loop. This may be a wrong explanation, but nevertheless it is the only thing I could think of.