James Shaw wrote:
Sorry about the delay in my reply. I have identified the problem when tabbing through enabled and disabled text ctrls.
If you put the control in a panel and disable one, tabbing works as expected - the caret moves between the two enabled ctrls.
If you use the sample code below, however, tabbing makes the caret disappear (the wxPanel containing the disabled control gets focus).
Here's the small piece of code:
--------------
from wxPython.wx import *
class myApplication(wxApp):
def OnInit(self):
# Create the GUI frames
self.frame = myFrame(NULL, -1, "Test")
self.SetTopWindow(self.frame)
self.frame.Show(true)
# All done
return true
class myFrame(wxFrame):
def __init__(self, parent, id, caption):
wxFrame.__init__(self, parent, id, caption)
panel = myPanel(self)
class myPanel(wxPanel):
def __init__(self, parent):
wxPanel.__init__(self, parent, -1)
entry1 = myLabelAndTextCtrl(self, TRUE)
entry2 = myLabelAndTextCtrl(self, FALSE)
entry3 = myLabelAndTextCtrl(self, TRUE)
sizer = wxBoxSizer(wxVERTICAL)
sizer.Add(entry1, 0)
sizer.Add(entry2, 0)
sizer.Add(entry3, 0)
self.SetAutoLayout(TRUE)
self.SetSizer(sizer)
sizer.Fit(self)
class myLabelAndTextCtrl(wxPanel):
def __init__(self, parent, enabled):
wxPanel.__init__(self, parent, -1)
label = wxStaticText(self, -1, "Text")
textCtrl = wxTextCtrl(self, -1)
textCtrl.Enable(enabled)
sizer = wxBoxSizer(wxHORIZONTAL)
sizer.Add(label, 1, wxEXPAND)
sizer.Add(textCtrl, 2, wxEXPAND)
self.SetAutoLayout(TRUE)
self.SetSizer(sizer)
sizer.Fit(self)
if __name__ == "__main__":
app = myApplication()
app.MainLoop()
-------------------
Any suggestions on how to fix this?
You can add
EVT_SET_FOCUS(self, self.OnFocus)
to myLabelAndTextCtrl.__init__, and then define self.OnFocus to check if the textCtrl.IsEnabled(). If not, you can set the focus to a different control, or post a NavigationKeyEvent to the parent panel to get it to send the focus on.
The tricky part is knowing whether the focus came from the previous control (e.g. via TAB) or the next control (e.g. via SHIFT-TAB). The following modifications to your myPanel and myLabelAndTextCtrl of your code work (at least with wxPython 2.3.2.1, Python 1.5.2 for Windows).
However, this solution requires you to manually tell each myLabelAndTextCtrl the ID of the previous control in the panel. Also, if the previous control was not a myLabelAndTextCtrl but a wxSomethingElse, you would also have to subclass wxSomethingElse and add a similar EVT_KILL_FOCUS handler.
...
class myPanel(wxPanel):
def __init__(self, parent):
wxPanel.__init__(self, parent, -1)
entry1 = myLabelAndTextCtrl(self, TRUE)
entry2 = myLabelAndTextCtrl(self, FALSE, entry1.GetId())
entry3 = myLabelAndTextCtrl(self, TRUE, entry2.GetId())
# note new final argument
entry1.set_preceding(entry3.GetId())
# unless we manually assign an ID to entry1, we can't set its preceding # control when we create it
self.most_recent_focus = entry1.GetId()
# don't think this is necessary any more now I figured out how to
# get OnLosingFocus to work
...
class myLabelAndTextCtrl(wxPanel):
def __init__(self, parent, enabled, preceding_id = None):
...
self.myText = textCtrl
self.preceding_id = preceding_id
EVT_SET_FOCUS(self, self.OnFocus)
EVT_KILL_FOCUS(self, self.OnLosingFocus)
EVT_KILL_FOCUS(textCtrl, self.OnLosingFocus)
# catch kill focus for both the textCtrl and the panel
def set_preceding(self, preceding_id):
self.preceding_id = preceding_id
def OnLosingFocus(self, focus_event):
self.GetParent().most_recent_focus = self.GetId()
def OnFocus(self, focus_event):
if not self.myText.IsEnabled():
# I think this condition is redundant. Tabbing never seems
# to give the focus to the panel unless the textCtrl is disabled.
parent = self.GetParent()
forward = (parent.most_recent_focus == self.preceding_id)
n = wxNavigationKeyEvent()
n.SetDirection(forward)
n.SetWindowChange(0)
n.SetEventObject(None)
# really, this should be the event emitter, but its only compared
# against the panel's parent to see if the event is propogating
# downward, so None seems to work
wxPostEvent(self.GetParent(), n)
Note: if ALL your text controls are disabled, the code about will lead to an infinite loop, so some error checking should be added to avoid that.
Also, the way I send the focus to the next control is a bit of a hack, because wxNavigationKeyEvent is not documented. I had to work out the details by looking at the src/generic/panelg.cpp and src/msw/window.cpp in the wxWindows source code.
David