2012-10-12 146 views
12

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

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

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

Respuesta

8

Este código Traverse enfoque Si presiona TAB y ficha Insertar si 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(); 
       } 

      } 
     } 
    }); 
+3

Un problema menor: debe tener una comprobación para event.isShiftDown() que debería llamar "TraversePrevious", no "TraverseNext". –

+4

Al menos para JavaFX 8, SkinBase debería cambiarse a TextAreaSkin. – tunabot

12

utilizo el transversales-métodos

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

Esta solución es la más limpia que encontré. Aunque no es necesario definirlo para TextFields, ya que esto ya es un valor predeterminado (al menos en Java 8). – codepleb

+0

Sin embargo, el problema es que lo obliga a extender TextArea, lo cual no es muy conveniente si usa Scene Builder. – User

+0

... en realidad @Override me echó de menos, no hay ningún método de control para anular en un TextArea, así que supongo que este es solo un método de control regular. Aún así, desearía que hubiera una manera más fácil, bueno. – User

0

tuve el mismo problema y me gusta 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"); 

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

Pero, 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.

Así que en lugar del método callAction(), que utiliza

textArea.replaceSelection("\t"); 
1

Si una solución diferente para el Tab - problema de enfoque. El comportamiento predeterminado de TextArea para la tecla CTRL + TAB es un movimiento de foco 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 desencadenar 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 eventos:

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

Inspirado por las respuestas anteriores y por un caso muy similar, he construido la clase siguiente:

/** 
* 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 h pestaña de navegación en el contexto de un campo de texto, así que eliminé esta parte.

Entonces esta clase se puede utilizar fácilmente como se describe por User:

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

Y todo funciona como un encanto :)

2

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

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

Tanto simular presionando CTRL+TAB cuando el usuario presiona TAB. El comportamiento predeterminado de TextArea para CTRL+TAB es mover el foco al siguiente control. Tenga en cuenta que el segundo código se basa en la respuesta de Johan De Schutter.

Cuestiones relacionadas