Tab 遍历不适用于 wx.TE_PROCESS_ENTER 和自动完成
Tab Traversal is not working with wx.TE_PROCESS_ENTER and AutoComplete
我正在尝试获取具有自动完成功能的 textCtrl,wx.TE_PROCESS_ENTER
已启用且选项卡遍历可以正常工作。
如果我禁用 wx.TE_PROCESS_ENTER
开关或不执行自动完成,则 Tab 遍历有效。
这里有一个小示例代码可以说明我的问题。
import wx
import wx.xrc
class MyFrame ( wx.Frame ):
def __init__( self, parent ):
wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size( -1,-1 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )
Sizer = wx.BoxSizer( wx.VERTICAL )
self.panel = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
inputSizer = wx.BoxSizer( wx.HORIZONTAL )
self.no_process_enter = wx.TextCtrl( self.panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
inputSizer.Add( self.no_process_enter, 0, wx.ALL, 5 )
self.no_autocomplete = wx.TextCtrl( self.panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_PROCESS_ENTER )
inputSizer.Add( self.no_autocomplete, 0, wx.ALL, 5 )
self.autocomplete_and_process_enter = wx.TextCtrl( self.panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_PROCESS_ENTER )
inputSizer.Add( self.autocomplete_and_process_enter, 0, wx.ALL, 5 )
ButtonSizer = wx.StdDialogButtonSizer()
self.ButtonSizerOK = wx.Button( self.panel, wx.ID_OK )
ButtonSizer.AddButton( self.ButtonSizerOK )
self.ButtonSizerCancel = wx.Button( self.panel, wx.ID_CANCEL )
ButtonSizer.AddButton( self.ButtonSizerCancel )
ButtonSizer.Realize();
inputSizer.Add( ButtonSizer, 1, wx.EXPAND, 5 )
self.panel.SetSizer( inputSizer )
self.panel.Layout()
inputSizer.Fit( self.panel )
Sizer.Add( self.panel, 1, wx.EXPAND |wx.ALL, 5 )
self.SetSizer( Sizer )
self.Layout()
self.Fit()
self.Centre( wx.BOTH )
# Connect Events
self.no_process_enter.Bind( wx.EVT_KILL_FOCUS, self.no_process_enterOnKillFocus )
self.no_process_enter.Bind( wx.EVT_SET_FOCUS, self.no_process_enterOnSetFocus )
self.no_process_enter.Bind( wx.EVT_KEY_DOWN, self.OnKeyDown )
self.no_autocomplete.Bind( wx.EVT_KILL_FOCUS, self.no_autocompleteOnKillFocus )
self.no_autocomplete.Bind( wx.EVT_SET_FOCUS, self.no_autocompleteOnSetFocus )
self.no_autocomplete.Bind( wx.EVT_TEXT_ENTER, self.no_autocompleteOnTextEnter )
self.no_autocomplete.Bind( wx.EVT_KEY_DOWN, self.OnKeyDown )
self.autocomplete_and_process_enter.Bind( wx.EVT_KILL_FOCUS, self.autocomplete_and_process_enterOnKillFocus )
self.autocomplete_and_process_enter.Bind( wx.EVT_SET_FOCUS, self.autocomplete_and_process_enterOnSetFocus )
self.autocomplete_and_process_enter.Bind( wx.EVT_TEXT_ENTER, self.autocomplete_and_process_enterOnTextEnter )
self.autocomplete_and_process_enter.Bind( wx.EVT_KEY_DOWN, self.OnKeyDown )
def __del__( self ):
pass
# Virtual event handlers, overide them in your derived class
def no_process_enterOnKillFocus( self, event ):
print('leave no_process_enter\n')
event.Skip()
def no_process_enterOnSetFocus( self, event ):
print('enter no_process_enter')
event.Skip()
def no_autocompleteOnKillFocus( self, event ):
print('leave no_autocomplete\n')
event.Skip()
def no_autocompleteOnSetFocus( self, event ):
print('enter no_autocomplete')
event.Skip()
def no_autocompleteOnTextEnter( self, event ):
print('no_autocomplete - ENTER pressed')
event.Skip()
def autocomplete_and_process_enterOnKillFocus( self, event ):
print('leave autocomplete_and_process_enter\n')
event.Skip()
def autocomplete_and_process_enterOnSetFocus( self, event ):
print('enter autocomplete_and_process_enter')
event.Skip()
def autocomplete_and_process_enterOnTextEnter( self, event ):
print('autocomplete_and_process_enter - ENTER pressed')
event.Skip()
def OnKeyDown( self, event ):
#print(event.GetKeyCode())
if event.GetKeyCode() == wx.WXK_TAB:
print('navigate to next element')
event.EventObject.Navigate()
event.Skip(False)
else:
event.Skip()
if __name__ == '__main__':
app = wx.App()
frame = MyFrame(None)
app.SetTopWindow(frame)
frame.Show(True)
frame.no_process_enter.AutoComplete(['Hello', 'World'])
frame.autocomplete_and_process_enter.AutoComplete(['Foo', 'Bar'])
app.MainLoop()
终于成功解决问题了。诀窍是在事件传递到事件链之前捕获事件并手动进行选项卡遍历。
为此,您必须实施 TryBefore
method and limits the execution to the text fields that do not work. To enable bidirectional navigation the parameter not event.ShiftDown()
is passed to the event.EventObject.Navigate
方法。
import wx
import wx.xrc
class MyFrame ( wx.Frame ):
def __init__( self, parent ):
wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size( -1,-1 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )
Sizer = wx.BoxSizer( wx.VERTICAL )
self.panel = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
inputSizer = wx.BoxSizer( wx.VERTICAL )
self.no_process_enter = wx.TextCtrl( self.panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
inputSizer.Add( self.no_process_enter, 0, wx.ALL, 5 )
self.no_autocomplete = wx.TextCtrl( self.panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_PROCESS_ENTER )
inputSizer.Add( self.no_autocomplete, 0, wx.ALL, 5 )
self.autocomplete_and_process_enter = wx.TextCtrl( self.panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_PROCESS_ENTER )
inputSizer.Add( self.autocomplete_and_process_enter, 0, wx.ALL, 5 )
ButtonSizer = wx.StdDialogButtonSizer()
self.ButtonSizerOK = wx.Button( self.panel, wx.ID_OK )
ButtonSizer.AddButton( self.ButtonSizerOK )
self.ButtonSizerCancel = wx.Button( self.panel, wx.ID_CANCEL )
ButtonSizer.AddButton( self.ButtonSizerCancel )
ButtonSizer.Realize();
inputSizer.Add( ButtonSizer, 1, wx.EXPAND, 5 )
self.panel.SetSizer( inputSizer )
self.panel.Layout()
inputSizer.Fit( self.panel )
Sizer.Add( self.panel, 1, wx.EXPAND |wx.ALL, 5 )
self.SetSizer( Sizer )
self.Layout()
self.Fit()
self.Centre( wx.BOTH )
# Connect Events
self.no_process_enter.Bind( wx.EVT_KILL_FOCUS, self.no_process_enterOnKillFocus )
self.no_process_enter.Bind( wx.EVT_SET_FOCUS, self.no_process_enterOnSetFocus )
self.no_autocomplete.Bind( wx.EVT_KILL_FOCUS, self.no_autocompleteOnKillFocus )
self.no_autocomplete.Bind( wx.EVT_SET_FOCUS, self.no_autocompleteOnSetFocus )
self.no_autocomplete.Bind( wx.EVT_TEXT_ENTER, self.no_autocompleteOnTextEnter )
self.autocomplete_and_process_enter.Bind( wx.EVT_KILL_FOCUS, self.autocomplete_and_process_enterOnKillFocus )
self.autocomplete_and_process_enter.Bind( wx.EVT_SET_FOCUS, self.autocomplete_and_process_enterOnSetFocus )
self.autocomplete_and_process_enter.Bind( wx.EVT_TEXT_ENTER, self.autocomplete_and_process_enterOnTextEnter )
def __del__( self ):
pass
def TryBefore(self, event):
if isinstance(event, wx.KeyEvent):
if event.GetEventObject().GetId() in (self.no_autocomplete.GetId(), self.autocomplete_and_process_enter.GetId()):
if event.GetKeyCode() == wx.WXK_TAB:
event.EventObject.Navigate(not event.ShiftDown())
return False
return wx.Frame.TryBefore(self, event)
# Virtual event handlers, overide them in your derived class
def no_process_enterOnKillFocus( self, event ):
print('leave no_process_enter\n')
event.Skip()
def no_process_enterOnSetFocus( self, event ):
print('enter no_process_enter')
event.Skip()
def no_autocompleteOnKillFocus( self, event ):
print('leave no_autocomplete\n')
event.Skip()
def no_autocompleteOnSetFocus( self, event ):
print('enter no_autocomplete')
event.Skip()
def no_autocompleteOnTextEnter( self, event ):
print('no_autocomplete - ENTER pressed')
event.Skip()
def autocomplete_and_process_enterOnKillFocus( self, event ):
print('leave autocomplete_and_process_enter\n')
event.Skip()
def autocomplete_and_process_enterOnSetFocus( self, event ):
print('enter autocomplete_and_process_enter')
event.Skip()
def autocomplete_and_process_enterOnTextEnter( self, event ):
print('autocomplete_and_process_enter - ENTER pressed')
event.Skip()
if __name__ == '__main__':
app = wx.App()
frame = MyFrame(None)
app.SetTopWindow(frame)
frame.Show(True)
frame.no_process_enter.AutoComplete(['Hello', 'World'])
frame.autocomplete_and_process_enter.AutoComplete(['Foo', 'Bar'])
app.MainLoop()
我正在尝试获取具有自动完成功能的 textCtrl,wx.TE_PROCESS_ENTER
已启用且选项卡遍历可以正常工作。
如果我禁用 wx.TE_PROCESS_ENTER
开关或不执行自动完成,则 Tab 遍历有效。
这里有一个小示例代码可以说明我的问题。
import wx
import wx.xrc
class MyFrame ( wx.Frame ):
def __init__( self, parent ):
wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size( -1,-1 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )
Sizer = wx.BoxSizer( wx.VERTICAL )
self.panel = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
inputSizer = wx.BoxSizer( wx.HORIZONTAL )
self.no_process_enter = wx.TextCtrl( self.panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
inputSizer.Add( self.no_process_enter, 0, wx.ALL, 5 )
self.no_autocomplete = wx.TextCtrl( self.panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_PROCESS_ENTER )
inputSizer.Add( self.no_autocomplete, 0, wx.ALL, 5 )
self.autocomplete_and_process_enter = wx.TextCtrl( self.panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_PROCESS_ENTER )
inputSizer.Add( self.autocomplete_and_process_enter, 0, wx.ALL, 5 )
ButtonSizer = wx.StdDialogButtonSizer()
self.ButtonSizerOK = wx.Button( self.panel, wx.ID_OK )
ButtonSizer.AddButton( self.ButtonSizerOK )
self.ButtonSizerCancel = wx.Button( self.panel, wx.ID_CANCEL )
ButtonSizer.AddButton( self.ButtonSizerCancel )
ButtonSizer.Realize();
inputSizer.Add( ButtonSizer, 1, wx.EXPAND, 5 )
self.panel.SetSizer( inputSizer )
self.panel.Layout()
inputSizer.Fit( self.panel )
Sizer.Add( self.panel, 1, wx.EXPAND |wx.ALL, 5 )
self.SetSizer( Sizer )
self.Layout()
self.Fit()
self.Centre( wx.BOTH )
# Connect Events
self.no_process_enter.Bind( wx.EVT_KILL_FOCUS, self.no_process_enterOnKillFocus )
self.no_process_enter.Bind( wx.EVT_SET_FOCUS, self.no_process_enterOnSetFocus )
self.no_process_enter.Bind( wx.EVT_KEY_DOWN, self.OnKeyDown )
self.no_autocomplete.Bind( wx.EVT_KILL_FOCUS, self.no_autocompleteOnKillFocus )
self.no_autocomplete.Bind( wx.EVT_SET_FOCUS, self.no_autocompleteOnSetFocus )
self.no_autocomplete.Bind( wx.EVT_TEXT_ENTER, self.no_autocompleteOnTextEnter )
self.no_autocomplete.Bind( wx.EVT_KEY_DOWN, self.OnKeyDown )
self.autocomplete_and_process_enter.Bind( wx.EVT_KILL_FOCUS, self.autocomplete_and_process_enterOnKillFocus )
self.autocomplete_and_process_enter.Bind( wx.EVT_SET_FOCUS, self.autocomplete_and_process_enterOnSetFocus )
self.autocomplete_and_process_enter.Bind( wx.EVT_TEXT_ENTER, self.autocomplete_and_process_enterOnTextEnter )
self.autocomplete_and_process_enter.Bind( wx.EVT_KEY_DOWN, self.OnKeyDown )
def __del__( self ):
pass
# Virtual event handlers, overide them in your derived class
def no_process_enterOnKillFocus( self, event ):
print('leave no_process_enter\n')
event.Skip()
def no_process_enterOnSetFocus( self, event ):
print('enter no_process_enter')
event.Skip()
def no_autocompleteOnKillFocus( self, event ):
print('leave no_autocomplete\n')
event.Skip()
def no_autocompleteOnSetFocus( self, event ):
print('enter no_autocomplete')
event.Skip()
def no_autocompleteOnTextEnter( self, event ):
print('no_autocomplete - ENTER pressed')
event.Skip()
def autocomplete_and_process_enterOnKillFocus( self, event ):
print('leave autocomplete_and_process_enter\n')
event.Skip()
def autocomplete_and_process_enterOnSetFocus( self, event ):
print('enter autocomplete_and_process_enter')
event.Skip()
def autocomplete_and_process_enterOnTextEnter( self, event ):
print('autocomplete_and_process_enter - ENTER pressed')
event.Skip()
def OnKeyDown( self, event ):
#print(event.GetKeyCode())
if event.GetKeyCode() == wx.WXK_TAB:
print('navigate to next element')
event.EventObject.Navigate()
event.Skip(False)
else:
event.Skip()
if __name__ == '__main__':
app = wx.App()
frame = MyFrame(None)
app.SetTopWindow(frame)
frame.Show(True)
frame.no_process_enter.AutoComplete(['Hello', 'World'])
frame.autocomplete_and_process_enter.AutoComplete(['Foo', 'Bar'])
app.MainLoop()
终于成功解决问题了。诀窍是在事件传递到事件链之前捕获事件并手动进行选项卡遍历。
为此,您必须实施 TryBefore
method and limits the execution to the text fields that do not work. To enable bidirectional navigation the parameter not event.ShiftDown()
is passed to the event.EventObject.Navigate
方法。
import wx
import wx.xrc
class MyFrame ( wx.Frame ):
def __init__( self, parent ):
wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size( -1,-1 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )
Sizer = wx.BoxSizer( wx.VERTICAL )
self.panel = wx.Panel( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TAB_TRAVERSAL )
inputSizer = wx.BoxSizer( wx.VERTICAL )
self.no_process_enter = wx.TextCtrl( self.panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
inputSizer.Add( self.no_process_enter, 0, wx.ALL, 5 )
self.no_autocomplete = wx.TextCtrl( self.panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_PROCESS_ENTER )
inputSizer.Add( self.no_autocomplete, 0, wx.ALL, 5 )
self.autocomplete_and_process_enter = wx.TextCtrl( self.panel, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_PROCESS_ENTER )
inputSizer.Add( self.autocomplete_and_process_enter, 0, wx.ALL, 5 )
ButtonSizer = wx.StdDialogButtonSizer()
self.ButtonSizerOK = wx.Button( self.panel, wx.ID_OK )
ButtonSizer.AddButton( self.ButtonSizerOK )
self.ButtonSizerCancel = wx.Button( self.panel, wx.ID_CANCEL )
ButtonSizer.AddButton( self.ButtonSizerCancel )
ButtonSizer.Realize();
inputSizer.Add( ButtonSizer, 1, wx.EXPAND, 5 )
self.panel.SetSizer( inputSizer )
self.panel.Layout()
inputSizer.Fit( self.panel )
Sizer.Add( self.panel, 1, wx.EXPAND |wx.ALL, 5 )
self.SetSizer( Sizer )
self.Layout()
self.Fit()
self.Centre( wx.BOTH )
# Connect Events
self.no_process_enter.Bind( wx.EVT_KILL_FOCUS, self.no_process_enterOnKillFocus )
self.no_process_enter.Bind( wx.EVT_SET_FOCUS, self.no_process_enterOnSetFocus )
self.no_autocomplete.Bind( wx.EVT_KILL_FOCUS, self.no_autocompleteOnKillFocus )
self.no_autocomplete.Bind( wx.EVT_SET_FOCUS, self.no_autocompleteOnSetFocus )
self.no_autocomplete.Bind( wx.EVT_TEXT_ENTER, self.no_autocompleteOnTextEnter )
self.autocomplete_and_process_enter.Bind( wx.EVT_KILL_FOCUS, self.autocomplete_and_process_enterOnKillFocus )
self.autocomplete_and_process_enter.Bind( wx.EVT_SET_FOCUS, self.autocomplete_and_process_enterOnSetFocus )
self.autocomplete_and_process_enter.Bind( wx.EVT_TEXT_ENTER, self.autocomplete_and_process_enterOnTextEnter )
def __del__( self ):
pass
def TryBefore(self, event):
if isinstance(event, wx.KeyEvent):
if event.GetEventObject().GetId() in (self.no_autocomplete.GetId(), self.autocomplete_and_process_enter.GetId()):
if event.GetKeyCode() == wx.WXK_TAB:
event.EventObject.Navigate(not event.ShiftDown())
return False
return wx.Frame.TryBefore(self, event)
# Virtual event handlers, overide them in your derived class
def no_process_enterOnKillFocus( self, event ):
print('leave no_process_enter\n')
event.Skip()
def no_process_enterOnSetFocus( self, event ):
print('enter no_process_enter')
event.Skip()
def no_autocompleteOnKillFocus( self, event ):
print('leave no_autocomplete\n')
event.Skip()
def no_autocompleteOnSetFocus( self, event ):
print('enter no_autocomplete')
event.Skip()
def no_autocompleteOnTextEnter( self, event ):
print('no_autocomplete - ENTER pressed')
event.Skip()
def autocomplete_and_process_enterOnKillFocus( self, event ):
print('leave autocomplete_and_process_enter\n')
event.Skip()
def autocomplete_and_process_enterOnSetFocus( self, event ):
print('enter autocomplete_and_process_enter')
event.Skip()
def autocomplete_and_process_enterOnTextEnter( self, event ):
print('autocomplete_and_process_enter - ENTER pressed')
event.Skip()
if __name__ == '__main__':
app = wx.App()
frame = MyFrame(None)
app.SetTopWindow(frame)
frame.Show(True)
frame.no_process_enter.AutoComplete(['Hello', 'World'])
frame.autocomplete_and_process_enter.AutoComplete(['Foo', 'Bar'])
app.MainLoop()