从英文直译的话,org.eclipse.swt.events.TraverseEvent是指widget中组件遍历(切换焦点)动作发生时产生的事件 举例来说,就是当我们使用光标键,TAB/shift-TAB键,PAGE-UP/DOWN等键在按钮(Button)之间切换焦点的时候,就会产生TraverseEvent事件。
关于TraverseEven的原文说明,参见官网《org.eclipse.swt.events.TraverseEvent》
当在Canvas中按下TAB键时, TraverseEvent#detail字段的值是SWT.TRAVERSE_TAB_NEXT ,TraverseEvent#doit 字段的值是false,这时系统的默认行为不会将这个TAB键理解为用户是想将焦点设置到下一个widget,这就意味着在Canvas中的按键侦听器(key Listener)将会收到用户敲的TAB键(SWT.TAB)—所以默认情况下,用TAB键是无法在widget之间切换焦点的。
如果要想让Composite对象支持TAB键在组件间移动焦点,就要改变系统对TAB键的行为,修改TraverseEvent#doit 字段的值为true
下面是org.eclipse.swt.widget.Control类中的traverse 方法代码,可以看到,当TraverseEvent#doit为true就会执行后续的遍历动作。
boolean traverse (Event event) { /* * It is possible (but unlikely), that application * code could have disposed the widget in the traverse * event. If this happens, return true to stop further * event processing. */ //将TraverseEvent事件发送给所有组件 sendEvent (SWT.Traverse, event); if (isDisposed ()) return true; if (!event.doit) return false; //如果有组件将响应TraverseEvent事件并将doit置为true,就执行遍历动作。 switch (event.detail) { case SWT.TRAVERSE_NONE: return true; case SWT.TRAVERSE_ESCAPE: return traverseEscape (); case SWT.TRAVERSE_RETURN: return traverseReturn (); case SWT.TRAVERSE_TAB_NEXT: return traverseGroup (true); case SWT.TRAVERSE_TAB_PREVIOUS: return traverseGroup (false); case SWT.TRAVERSE_ARROW_NEXT: return traverseItem (true); case SWT.TRAVERSE_ARROW_PREVIOUS: return traverseItem (false); case SWT.TRAVERSE_MNEMONIC: return traverseMnemonic (event.character); case SWT.TRAVERSE_PAGE_NEXT: return traversePage (true); case SWT.TRAVERSE_PAGE_PREVIOUS: return traversePage (false); } return false; }如何将doit置为true呢? SWT提供了一个TraverseListener接口(遍历事件侦听器),在组件上加上这个侦听器,就可以收到并处理TraverseEvent事件。
在WindowBuilder下添加TraverseListener侦听器很方便,可以如下图在组件上右键点击,找到Add event handler\traverse\keyTraversed,就可以为组件添加一个TraverseListener了。
然后在侦听器中添加如下处理代码(是参照org.eclipse.ui.forms.widgets.FormText的TraverseListener代码改的):
addTraverseListener(new TraverseListener() { @Override public void keyTraversed(TraverseEvent e) { switch (e.detail) { case SWT.TRAVERSE_TAB_NEXT: case SWT.TRAVERSE_TAB_PREVIOUS: // TAB/shift-TAB键时将doit置为true e.doit = true; return; } } });上面的代码也可以写成这样
addListener(SWT.Traverse, new Listener() { @Override public void handleEvent(Event e) { switch (e.detail) { case SWT.TRAVERSE_TAB_NEXT: case SWT.TRAVERSE_TAB_PREVIOUS: e.doit = true; return; } } });注意:不要忘记在父类中调用setTabList设置TAB list
《SWT对于监听Tab键的理解》 《org.eclipse.swt.events.TraverseEvent》 《SWT/JFace 按键、事件、监听》
