JavaFX TextArea中的Tab键导航

如何在TextArea中按Tab键导航到下一个控件?

我可以为cath de key按下事件添加一个监听器,但是如何使te TextArea控件失去焦点(不知道要聚焦的链中的下一个字段)?

@FXML protected void handleTabKeyTextArea(KeyEvent event) { if (event.getCode() == KeyCode.TAB) { ... } } 

如果按TAB键,则此代码遍历焦点,如果按CONTROL + TAB,则插入选项卡

 textArea.addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler() { @Override public void handle(KeyEvent event) { if (event.getCode() == KeyCode.TAB) { SkinBase skin = (SkinBase) textArea.getSkin(); if (skin.getBehavior() instanceof TextAreaBehavior) { TextAreaBehavior behavior = (TextAreaBehavior) skin.getBehavior(); if (event.isControlDown()) { behavior.callAction("InsertTab"); } else { behavior.callAction("TraverseNext"); } event.consume(); } } } }); 

我使用遍历方法

 @Override public void handle(KeyEvent event) { if (event.getCode().equals(KeyCode.TAB)) { Node node = (Node) event.getSource(); if (node instanceof TextField) { TextFieldSkin skin = (TextFieldSkin) ((TextField)node).getSkin(); if (event.isShiftDown()) { skin.getBehavior().traversePrevious(); } else { skin.getBehavior().traverseNext(); } } else if (node instanceof TextArea) { TextAreaSkin skin = (TextAreaSkin) ((TextArea)node).getSkin(); if (event.isShiftDown()) { skin.getBehavior().traversePrevious(); } else { skin.getBehavior().traverseNext(); } } event.consume(); } } 

从Java 9(2017)开始 ,此页面中的大多数答案都不起作用,因为您不能再执行skin.getBehavior()了。

这有效:

 @Override public void handle(KeyEvent event) { KeyCode code = event.getCode(); if (code == KeyCode.TAB && !event.isShiftDown() && !event.isControlDown()) { event.consume(); Node node = (Node) event.getSource(); try { Robot robot = new Robot(); robot.keyPress(KeyCode.CONTROL.getCode()); robot.keyPress(KeyCode.TAB.getCode()); robot.delay(10); robot.keyRelease(KeyCode.TAB.getCode()); robot.keyRelease(KeyCode.CONTROL.getCode()); } catch (AWTException e) { } } } 

这也有效:

 @Override public void handle(KeyEvent event) { KeyCode code = event.getCode(); if (code == KeyCode.TAB && !event.isShiftDown() && !event.isControlDown()) { event.consume(); Node node = (Node) event.getSource(); KeyEvent newEvent = new KeyEvent(event.getSource(), event.getTarget(), event.getEventType(), event.getCharacter(), event.getText(), event.getCode(), event.isShiftDown(), true, event.isAltDown(), event.isMetaDown()); node.fireEvent(newEvent); } } 

当用户按下TAB时,两者都模拟按CTRL+TAB TABCTRL+TAB的TextArea的默认行为是将焦点移动到下一个控件。 请注意,第二个代码基于Johan De Schutter的答案。

如果Tab-Focus问题有不同的解决方案。 CTRL + TAB键的TextArea的默认行为是将焦点移动到下一个控件。 所以我用CTRL + TAB键事件替换了TAB键事件,当用户点击CTRL + TAB时,在TextArea中插入了一个制表符。

我的问题:在事件filter中触发事件是否可以? 可以用FOCUS_EVENT_TEXT替换KeyEvent的文本,以便指示它是用户生成的事件,还是事件filter中创建的事件。

事件filter:

 javafx.scene.control.TextArea textArea1 = new javafx.scene.control.TextArea(); textArea1.addEventFilter(KeyEvent.KEY_PRESSED, new TextAreaTabToFocusEventHandler()); 

事件处理程序:

 public class TextAreaTabToFocusEventHandler implements EventHandler { private static final String FOCUS_EVENT_TEXT = "TAB_TO_FOCUS_EVENT"; @Override public void handle(final KeyEvent event) { if (!KeyCode.TAB.equals(event.getCode())) { return; } // handle events where the TAB key or TAB + CTRL key is pressed // so don't handle the event if the ALT, SHIFT or any other modifier key is pressed if (event.isAltDown() || event.isMetaDown() || event.isShiftDown()) { return; } if (!(event.getSource() instanceof TextArea)) { return; } final TextArea textArea = (TextArea) event.getSource(); if (event.isControlDown()) { // if the event text contains the special focus event text // => do not consume the event, and let the default behaviour (= move focus to the next control) happen. // // if the focus event text is not present, then the user has pressed CTRL + TAB key, // then consume the event and insert or replace selection with tab character if (!FOCUS_EVENT_TEXT.equalsIgnoreCase(event.getText())) { event.consume(); textArea.replaceSelection("\t"); } } else { // The default behaviour of the TextArea for the CTRL+TAB key is a move of focus to the next control. // So we consume the TAB key event, and fire a new event with the CTRL + TAB key. event.consume(); final KeyEvent tabControlEvent = new KeyEvent(event.getSource(), event.getTarget(), event.getEventType(), event.getCharacter(), FOCUS_EVENT_TEXT, event.getCode(), event.isShiftDown(), true, event.isAltDown(), event.isMetaDown()); textArea.fireEvent(tabControlEvent); } } } 

受到之前答案的启发,对于一个非常类似的案例,我构建了以下类:

 /** * Handles tab/shift-tab keystrokes to navigate to other fields, * ctrl-tab to insert a tab character in the text area. */ public class TabTraversalEventHandler implements EventHandler { @Override public void handle(KeyEvent event) { if (event.getCode().equals(KeyCode.TAB)) { Node node = (Node) event.getSource(); if (node instanceof TextArea) { TextAreaSkin skin = (TextAreaSkin) ((TextArea)node).getSkin(); if (!event.isControlDown()) { // Tab or shift-tab => navigational action if (event.isShiftDown()) { skin.getBehavior().traversePrevious(); } else { skin.getBehavior().traverseNext(); } } else { // Ctrl-Tab => insert a tab character in the text area TextArea textArea = (TextArea) node; textArea.replaceSelection("\t"); } event.consume(); } } } } 

我只是没有看到在TextField的上下文中处理tab的必要性所以我删除了这部分。

然后, 用户可以很容易地使用这个类:

 TextArea myTextArea = new TextArea(); mytTextArea.addEventFilter(KeyEvent.KEY_PRESSED, new TabTraversalEventHandler()); 

整个事情就像一个魅力:)

我有同样的问题,我喜欢汤姆使用的遍历方法。 但是我也想在按下ctrl + tab时插入一个标签。

电话

 behavior.callAction("InsertTab"); 

不适用于JavaFX8。 在TextAreaBehaviour类中看一下,现在有一个“TraverseOrInsertTab”动作。

但是,我认为这种动作调用在几个java版本中非常不稳定,因为它依赖于传递的字符串。

所以我用了而不是callAction()方法

 textArea.replaceSelection("\t");