Finding which control has focus

I have a frame that contains 6 controls: ComboBox, ExpandoTextCtrl, and 2 list controls, cancel button, send button. I want to know if there is some way to
trap the fact that a user clicked the mouse on the ComboBox, ExpandoTextCtrl or
either of the 2 list controls. I would like to make the label bold to show which control has the focus. onSetFocus/onKillFocus doesn't fire when you click on these controls. I can't even get it to fire when I do MyExpandoTextCtrl.SetFocus() (but the focus does change) Is there some other way? I don't have these on separate windows or panels.

Thanks in advance.
Larry Bates

Larry Bates wrote:

I have a frame that contains 6 controls: ComboBox, ExpandoTextCtrl, and 2 list controls, cancel button, send button. I want to know if there is some way to
trap the fact that a user clicked the mouse on the ComboBox, ExpandoTextCtrl or
either of the 2 list controls. I would like to make the label bold to show which control has the focus. onSetFocus/onKillFocus doesn't fire when you click on these controls. I can't even get it to fire when I do MyExpandoTextCtrl.SetFocus() (but the focus does change) Is there some other way? I don't have these on separate windows or panels.

How are you binding the events to those methods? (Some sample code is worth 1000 words...)

To answer the question in your Subject, there is the wx.Window.FindFocus static method.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Robin Dunn wrote:

Larry Bates wrote:

I have a frame that contains 6 controls: ComboBox, ExpandoTextCtrl, and 2 list controls, cancel button, send button. I want to know if there is some way to
trap the fact that a user clicked the mouse on the ComboBox, ExpandoTextCtrl or
either of the 2 list controls. I would like to make the label bold to show which control has the focus. onSetFocus/onKillFocus doesn't fire when you click on these controls. I can't even get it to fire when I do MyExpandoTextCtrl.SetFocus() (but the focus does change) Is there some other way? I don't have these on separate windows or panels.

How are you binding the events to those methods? (Some sample code is worth 1000 words...)

To answer the question in your Subject, there is the wx.Window.FindFocus static method.

Here is a working example of my problem. I've stripped it down as much as I could. I just can't seem to get any of the focus events to fire/call my methods. Thanks for taking a look.

Regards,
Larry

import wx
from wx.lib.expando import ExpandoTextCtrl
import wx.lib.mixins.listctrl as listmix

···

#----------------------------------------------------------------------

class usernamesListCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin):

     def __init__(self, parent, ID, style=0, pos=wx.DefaultPosition,
                                             size=wx.DefaultSize):
         wx.ListCtrl.__init__(self, parent, ID, pos, size, style)
         #
         # Use ListCtrlAutoWidthMixin to extend the width of the last column so
         # that it fills line to the end of the table.
         #
         listmix.ListCtrlAutoWidthMixin.__init__(self)
         #
         # Insert 2 columns in the usernames list (name, email)
         #
         self.InsertColumn(0, 'Name', format=wx.LIST_FORMAT_LEFT, width=180)
         self.InsertColumn(1, 'Username', format=wx.LIST_FORMAT_LEFT, width=-1)

     def onSetFocus(self, event):
         print "LCU.onSetFocus triggered"
         window=self.FindFocus()
         print "LCU window=", window
         event.Skip()

     def onKillFocus(self, event):
         print "LCU.onKillFocus triggered"
         window=self.FindFocus()
         print "LCU window=", window
         event.Skip()

class filenamesListCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin):
# listmix.ColumnSorterMixin):

     def __init__(self, parent, ID, pos=wx.DefaultPosition,
                  size=wx.DefaultSize, style=0):
         wx.ListCtrl.__init__(self, parent, ID, pos, size, style)
         #
         # Use ListCtrlAutoWidthMixin to extend the width of the last column so
         # that it fills line to the end of the table.
         #
         listmix.ListCtrlAutoWidthMixin.__init__(self)
         #
         # Insert 2 columns in the filenames list (filename, size)
         #
         self.InsertColumn(0, 'Filename', format=wx.LIST_FORMAT_LEFT, width=350)
         self.InsertColumn(1, 'Size', format=wx.LIST_FORMAT_RIGHT, width=-1)

     def onSetFocus(self, event):
         print "LCF.onSetFocus triggered"
         window=self.FindFocus()
         print "LCF window=", window
         event.Skip()

     def onKillFocus(self, event):
         print "LCF.onKillFocus triggered"
         window=self.FindFocus()
         print "LCF window=", window
         event.Skip()

class fromComboBox(wx.ComboBox):
     '''
     fromComboBox - This class handles the From: combo box
     '''
     def __init__(self, parent):
         self.parent=parent

         wx.ComboBox.__init__(self, parent, -1,
                              pos=(0,0), size=(-1,-1),
                         style=wx.CB_DROPDOWN | wx.CB_SORT | wx.TE_PROCESS_ENTER)

     def onSetFocus(self, event):
         print "FCB.onSetFocus triggered"
         window=self.FindFocus()
         print "FCB window=", window
         event.Skip()

     def onKillFocus(self, event):
         print "FCB.onKillFocus triggered"
         window=self.FindFocus()
         print "FCB window=", window
         event.Skip()

class toExpandoTextCtrl(ExpandoTextCtrl):
     def onSetFocus(self, event):
         print "TTC.onSetFocus triggered"
         window=self.FindFocus()
         print "TTC window=", window
         event.Skip()

     def onKillFocus(self, event):
         print "TTC.onKillFocus triggered"
         window=self.FindFocus()
         print "TTC window=", window
         event.Skip()

class MyFrame(wx.Frame):
     def __init__(self, *args, **kwds):
         wx.Frame.__init__(self, *args, **kwds)
         self.Centre(wx.HORIZONTAL)
         self.STS = self.CreateStatusBar(1)
         # -----From: Combo box ------------------------------------------------
         self.label_from = wx.StaticText(self, -1, "From:")
         self.FCB=fromComboBox(self)
         # -----To: Expando text control ----------------------------------------
         self.label_to = wx.StaticText(self, -1, "To:")
         self.TTC=toExpandoTextCtrl(self, size=(-1, -1))
         self.TTC.SetFocus()
         # -----Search instructions --------------------------------------------
         msg="(type a few characters of the name or email address to filter " \
             "the list)"
         self.label_searchinstructions = wx.StaticText(self, -1, msg)
         # -----Usernames list control -----------------------------------------
         hdr="WebSafe users that have given you a key:"
         self.sizer_usernames_staticbox = wx.StaticBox(self, -1, hdr)
         self.LCU=usernamesListCtrl(self, -1, style=wx.LC_REPORT|
                                                    wx.SUNKEN_BORDER|
                                                    wx.LC_HRULES |
                                                    wx.LC_VRULES)

         # -----Filenames list control -----------------------------------------
         msg="Files to be sent:"
         self.sizer_filenames_staticbox = wx.StaticBox(self, -1, msg)
         self.LCF=filenamesListCtrl(self, -1, style=wx.LC_REPORT|
                                                    wx.SUNKEN_BORDER|
                                                    wx.LC_HRULES |
                                                    wx.LC_VRULES)

         # -----Cancel & Send buttons ------------------------------------------
         self.button_cancel = wx.Button(self, -1, "Cancel")
         self.button_send = wx.Button(self, -1, "Send")
         self.__set_properties()
         self.__do_layout()
         # -----Bind events to the appropriate handlers ------------------------
         self.Bind(wx.EVT_SET_FOCUS, self.onSetFocus)
         self.Bind(wx.EVT_KILL_FOCUS, self.onKillFocus)
         self.Bind(wx.EVT_SET_FOCUS, self.FCB.onSetFocus, self.FCB)
         self.Bind(wx.EVT_KILL_FOCUS, self.TTC.onKillFocus, self.FCB)
         self.Bind(wx.EVT_SET_FOCUS, self.TTC.onSetFocus, self.TTC)
         self.Bind(wx.EVT_KILL_FOCUS, self.TTC.onKillFocus, self.TTC)
         self.Bind(wx.EVT_SET_FOCUS, self.LCU.onSetFocus, self.LCU)
         self.Bind(wx.EVT_KILL_FOCUS, self.LCU.onKillFocus, self.LCU)
         self.Bind(wx.EVT_SET_FOCUS, self.LCF.onSetFocus, self.LCF)
         self.Bind(wx.EVT_KILL_FOCUS, self.LCF.onKillFocus, self.LCF)
         return

     def __set_properties(self):
         self.SetTitle("WebSafe SendTo")
         frameSize=(560, -1)
         self.SetSize(frameSize)
         self.SetMinSize(frameSize)
         self.LCU.SetMinSize((-1,200))
         self.LCF.SetMinSize((-1,160))
         bgc=wx.SystemSettings_GetColour(wx.SYS_COLOUR_MENUBAR)
         self.SetBackgroundColour(bgc)
         self.label_searchinstructions.SetFont(wx.Font(7.5, wx.DEFAULT,
                                               wx.NORMAL, wx.NORMAL, 0, ""))

     def __do_layout(self):
         sizer_frame = wx.BoxSizer(wx.VERTICAL)
         grid_sizer_main = wx.FlexGridSizer(5, 2, 5, 5)
         grid_sizer_buttons = wx.FlexGridSizer(1, 3, 0, 0)
         sizer_filenames = wx.StaticBoxSizer(self.sizer_filenames_staticbox,
                                             wx.HORIZONTAL)
         sizer_usernames = wx.StaticBoxSizer(self.sizer_usernames_staticbox,
                                             wx.HORIZONTAL)
         sizer_6 = wx.BoxSizer(wx.HORIZONTAL)
         grid_sizer_main.Add(self.label_from, 0,
                             wx.RIGHT|wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, 0)

         grid_sizer_main.Add(self.FCB, 0, wx.EXPAND, 0)
         grid_sizer_main.Add(self.label_to, 0,
                             wx.RIGHT|wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL, 0)

         grid_sizer_main.Add(self.TTC, 0, wx.EXPAND, 0)
         grid_sizer_main.Add((20,20), 0, 0, 0, 0)
         sizer_6.Add((0,30), 0, 0, 0, 0)
         sizer_6.Add(self.label_searchinstructions, 0,
                     wx.LEFT|wx.RIGHT|wx.ALIGN_TOP, 5)

         grid_sizer_main.Add(sizer_6, 1, wx.EXPAND, 0)
         grid_sizer_main.Add((20, 20), 0, 0, 0)
         sizer_usernames.Add(self.LCU, 1, wx.EXPAND, 0)
         grid_sizer_main.Add(sizer_usernames, 1, wx.EXPAND, 0)
         grid_sizer_main.Add((20, 20), 0, 0, 0)
         sizer_filenames.Add(self.LCF, 1, wx.EXPAND, 0)
         grid_sizer_main.Add(sizer_filenames, 1, wx.EXPAND, 0)
         grid_sizer_main.Add((20, 20), 0, 0, 0)
         grid_sizer_buttons.Add((20, 20), 0, 0, 0)
         grid_sizer_buttons.Add(self.button_cancel, 0, 0, 0)
         grid_sizer_buttons.Add(self.button_send, 0, wx.LEFT, 10)
         grid_sizer_buttons.AddGrowableCol(0)
         grid_sizer_main.Add(grid_sizer_buttons, 1, wx.EXPAND, 0)
         grid_sizer_main.AddGrowableRow(2)
         grid_sizer_main.AddGrowableRow(3)
         grid_sizer_main.AddGrowableCol(1)
         sizer_frame.Add(grid_sizer_main, 1, wx.ALL|wx.EXPAND, 10)
         self.SetSizer(sizer_frame)
         self.Layout()
         self.Fit()

     def onSetFocus(self, event):
         print "MyFrame.onSetFocus triggered"
         window=self.FindFocus()
         print "MyFrame onSetFocus window=", window
         event.Skip()

     def onKillFocus(self, event):
         print "MyFrame.onKill Focus triggered"
         window=self.FindFocus()
         print "MyFrame onKillFocus window=", window
         event.Skip()

if __name__ == "__main__":
     #
     # Define instance wxWindows
     #
     app=wx.PySimpleApp(0)
     wx.InitAllImageHandlers()
     frame_1 = MyFrame(None, -1, "",)
     app.SetTopWindow(frame_1)
     frame_1.Show()
     #
     # All done, remove the message.
     #
     app.MainLoop()

Larry Bates wrote:

Robin Dunn wrote:

Larry Bates wrote:

I have a frame that contains 6 controls: ComboBox, ExpandoTextCtrl, and 2 list controls, cancel button, send button. I want to know if there is some way to
trap the fact that a user clicked the mouse on the ComboBox, ExpandoTextCtrl or
either of the 2 list controls. I would like to make the label bold to show which control has the focus. onSetFocus/onKillFocus doesn't fire when you click on these controls. I can't even get it to fire when I do MyExpandoTextCtrl.SetFocus() (but the focus does change) Is there some other way? I don't have these on separate windows or panels.

How are you binding the events to those methods? (Some sample code is worth 1000 words...)

To answer the question in your Subject, there is the wx.Window.FindFocus static method.

Here is a working example of my problem. I've stripped it down as much as I could. I just can't seem to get any of the focus events to fire/call my methods. Thanks for taking a look.

        self.Bind(wx.EVT_SET_FOCUS, self.onSetFocus)
        self.Bind(wx.EVT_KILL_FOCUS, self.onKillFocus)
        self.Bind(wx.EVT_SET_FOCUS, self.FCB.onSetFocus, self.FCB)
        self.Bind(wx.EVT_KILL_FOCUS, self.TTC.onKillFocus, self.FCB)
        self.Bind(wx.EVT_SET_FOCUS, self.TTC.onSetFocus, self.TTC)
        self.Bind(wx.EVT_KILL_FOCUS, self.TTC.onKillFocus, self.TTC)
        self.Bind(wx.EVT_SET_FOCUS, self.LCU.onSetFocus, self.LCU)
        self.Bind(wx.EVT_KILL_FOCUS, self.LCU.onKillFocus, self.LCU)
        self.Bind(wx.EVT_SET_FOCUS, self.LCF.onSetFocus, self.LCF)
        self.Bind(wx.EVT_KILL_FOCUS, self.LCF.onKillFocus, self.LCF)

Change these to look like this instead:

  self.FCB.Bind(wx.EVT_SET_FOCUS, self.FCB.onSetFocus)

(or move them into the other classes to better encapsulate the functionality.) You can read self.Bind vs. self.button.Bind - wxPyWiki for an explanation of the difference. (Hint: focus events are not command events.)

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Robin Dunn wrote:

(or move them into the other classes to better encapsulate the functionality.)

exactly. Read:

http://wiki.wxpython.org/wxPython_Style_Guide

In general, you don't want to have all these nested objects in one class -- and this is one of the reasons. there are a lot of posts on this list from people having trouble due to these kinds of problems.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

Robin Dunn wrote:

Larry Bates wrote:

Robin Dunn wrote:

Larry Bates wrote:

I have a frame that contains 6 controls: ComboBox, ExpandoTextCtrl, and 2 list controls, cancel button, send button. I want to know if there is some way to
trap the fact that a user clicked the mouse on the ComboBox, ExpandoTextCtrl or
either of the 2 list controls. I would like to make the label bold to show which control has the focus. onSetFocus/onKillFocus doesn't fire when you click on these controls. I can't even get it to fire when I do MyExpandoTextCtrl.SetFocus() (but the focus does change) Is there some other way? I don't have these on separate windows or panels.

How are you binding the events to those methods? (Some sample code is worth 1000 words...)

To answer the question in your Subject, there is the wx.Window.FindFocus static method.

Here is a working example of my problem. I've stripped it down as much as I could. I just can't seem to get any of the focus events to fire/call my methods. Thanks for taking a look.

        self.Bind(wx.EVT_SET_FOCUS, self.onSetFocus)
        self.Bind(wx.EVT_KILL_FOCUS, self.onKillFocus)
        self.Bind(wx.EVT_SET_FOCUS, self.FCB.onSetFocus, self.FCB)
        self.Bind(wx.EVT_KILL_FOCUS, self.TTC.onKillFocus, self.FCB)
        self.Bind(wx.EVT_SET_FOCUS, self.TTC.onSetFocus, self.TTC)
        self.Bind(wx.EVT_KILL_FOCUS, self.TTC.onKillFocus, self.TTC)
        self.Bind(wx.EVT_SET_FOCUS, self.LCU.onSetFocus, self.LCU)
        self.Bind(wx.EVT_KILL_FOCUS, self.LCU.onKillFocus, self.LCU)
        self.Bind(wx.EVT_SET_FOCUS, self.LCF.onSetFocus, self.LCF)
        self.Bind(wx.EVT_KILL_FOCUS, self.LCF.onKillFocus, self.LCF)

Change these to look like this instead:

    self.FCB.Bind(wx.EVT_SET_FOCUS, self.FCB.onSetFocus)

(or move them into the other classes to better encapsulate the functionality.) You can read self.Bind vs. self.button.Bind - wxPyWiki for an explanation of the difference. (Hint: focus events are not command events.)

Thanks for the tip. I'll review the style guide in some detail. This is my first REAL wx project, so I'm learning a lot. I have to admit that much of the "structure" was done for me by wxGlade. Perhaps it doesn't do the best job but it sure helped a LOT.

-Larry

Robin Dunn wrote:

(or move them into the other classes to better encapsulate the
functionality.)

exactly. Read:

http://wiki.wxpython.org/wxPython_Style_Guide

When I run the example program 'out of the box', I get an exception on line 21: AttributeError: can't set attribute

When I change the line to self.parent = ... (lowercase 'p'arent) it does not give the exception.

FWIW, I am running Python-2.5.1 and wxPython-2.8.6.0.

···

On Fri, 05 Oct 2007 14:24:55 -0700, you wrote:

In general, you don't want to have all these nested objects in one class
-- and this is one of the reasons. there are a lot of posts on this list
from people having trouble due to these kinds of problems.

-Chris

Ton van Vliet wrote:

···

On Fri, 05 Oct 2007 14:24:55 -0700, you wrote:

Robin Dunn wrote:

(or move them into the other classes to better encapsulate the functionality.)

exactly. Read:

http://wiki.wxpython.org/wxPython_Style_Guide

When I run the example program 'out of the box', I get an exception on line 21: AttributeError: can't set attribute

When I change the line to self.parent = ... (lowercase 'p'arent) it does not give the exception.

Yep. Parent (capital P) is now a property that maps to GetParent with no setter function. I'll change the page.

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!