jfoenix how example create application java user-interface javafx-2 javafx

how - javafx scene builder



NavegaciĆ³n con la tecla Tab en JavaFX TextArea (6)

¿Cómo hago para que al presionar la tecla Tab en TextArea navegue al siguiente control?

Podría agregar un oyente al evento presionado de cath de key, pero ¿cómo puedo hacer que el control TextArea pierda su foco (sin saber que el próximo campo de la cadena se enfocará)?

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


Este código atraviesa el foco si presiona TAB e inserta la pestaña si presiona CONTROL + TAB

textArea.addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() { @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(); } } } });


Yo uso los métodos transversales

@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(); } }


Tuve el mismo problema y me gustan los métodos transversales que usa Tom. Pero también quiero insertar una pestaña cuando se presiona ctrl + tab.

La llamada

behavior.callAction("InsertTab");

no funciona con JavaFX8. Una mirada en la clase TextAreaBehaviour me mostró que ahora hay una acción "TraverseOrInsertTab".

Sin embargo, creo que este tipo de llamadas de acción es bastante inestable en varias versiones de Java porque se basa en una cadena que se pasa.

Entonces, en lugar del método callAction (), utilicé

textArea.replaceSelection("/t");


Si es una solución diferente para la Pestaña - Problema de enfoque. El comportamiento predeterminado de TextArea para la tecla CTRL + TAB es un movimiento de enfoque al siguiente control. Así que reemplacé el evento de tecla TAB con un evento de tecla CTRL + TAB, y cuando el usuario pulsa CTRL + TAB, se inserta un carácter de tabulación en TextArea.

Mi pregunta: ¿está bien disparar un evento en el filtro de eventos? Y está bien reemplazar el texto del KeyEvent con el FOCUS_EVENT_TEXT, para tener una indicación si se trata de un evento generado por el usuario o del evento creado en el filtro de eventos.

El filtro de evento:

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

El controlador de eventos:

public class TextAreaTabToFocusEventHandler implements EventHandler<KeyEvent> { 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); } } }


Inspirado por las respuestas anteriores y para un caso muy similar, construí la siguiente clase:

/** * 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<KeyEvent> { @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(); } } } }

Simplemente no he visto la necesidad de manejar la pestaña en el contexto de un TextField, así que eliminé esta parte.

Entonces esta clase se puede usar muy fácilmente según lo descrito por el usuario :

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

Y todo funciona como un encanto :)


A partir de Java 9 (2017) , la mayoría de las respuestas en esta página no funcionan, ya que no puedes hacer más skin.getBehavior() .

Esto funciona:

@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) { } } }

Esto también funciona:

@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); } }

Ambos simulan presionar CTRL+TAB cuando el usuario presiona TAB . El comportamiento predeterminado de TextArea para CTRL+TAB mueve el foco al siguiente control. Tenga en cuenta que el segundo código se basa en la respuesta de Johan De Schutter.