2012-10-12 17 views
12

Come faccio a premere il tasto Tab in TextArea per passare al controllo successivo?Navigazione tramite tasto di tabulazione in JavaFX TextArea

Potrei aggiungere un ascoltatore all'evento premuto di cath de key, ma come faccio a fare in modo che il controllo TextArea perda il focus (senza conoscere il prossimo campo della catena da mettere a fuoco)?

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

risposta

8

Questo codice Traverse concentrarsi se premendo TAB ed inserire se premendo CTRL + 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 minore: dovrebbe avere un controllo per event.isShiftDown() che dovrebbe chiamare "TraversePrevious", non "TraverseNext". –

+4

Almeno per JavaFX 8, SkinBase deve essere modificato in TextAreaSkin. – tunabot

12

Io uso la traversata-metodi

@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

Questa soluzione è la più pulita che ho trovato. Sebbene non sia necessario definirlo per TextFields, poiché questo è già un valore predefinito (almeno in Java 8). – codepleb

+0

Tuttavia, il problema è che ti costringe ad estendere TextArea - non molto comodo se usi Scene Builder. – User

+0

... in realtà @Override mi ha buttato via, non esiste un metodo handle per sovrascrivere un TextArea, quindi immagino che questo sia solo un metodo di gestione regolare. Tuttavia, vorrei che ci fosse un modo più semplice - oh, va bene. – User

0

ho avuto lo stesso problema e mi piace i metodi trasversali che Tom usa. Ma voglio anche inserire una scheda quando si preme ctrl + tab.

La chiamata

behavior.callAction("InsertTab"); 

lavoro Indifferente con JavaFX8. Un'occhiata nella classe TextAreaBehaviour mi ha mostrato che ora esiste un'azione "TraverseOrInsertTab".

Tuttavia, penso che questo tipo di chiamata di azione sia piuttosto instabile tra diverse versioni di Java perché si basa su una stringa che viene passata.

Così, invece del metodo callAction(), ho usato

textArea.replaceSelection("\t"); 
1

Se una soluzione diversa per il Tab - problema di messa a fuoco. Il comportamento predefinito di TextArea per il tasto CTRL + TAB è uno spostamento del focus al controllo successivo. Quindi ho sostituito l'evento del tasto TAB con un evento di tasto CTRL + TAB e quando l'utente preme CTRL + TAB viene inserito un carattere di tabulazione in TextArea.

La mia domanda: è OK attivare un evento nel filtro eventi? E va bene sostituire il testo di KeyEvent con FOCUS_EVENT_TEXT, in modo da avere un'indicazione se si tratta di un evento generato dall'utente o dall'evento creato nel filtro eventi.

Il filtro evento:

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

Il gestore di eventi:

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

Ispirato dalle risposte precedenti e per un caso molto simile, ho costruito la seguente classe:

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

Non ho visto la necessità di h andling tab nel contesto di un campo di testo quindi ho rimosso questa parte.

Allora questa classe può essere utilizzata con estrema facilità, come descritto da User:

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

E il tutto funziona come un fascino :)

2

Come di Java 9 (2017), la maggior parte delle risposte in questa pagina non funzionano, dal momento che non è più possibile fare skin.getBehavior().

Questo funziona:

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

Questo funziona anche:

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

Sia simulare premendo CTRL+TAB quando l'utente preme TAB. Il comportamento predefinito di TextArea per CTRL+TAB sposta lo stato attivo sul controllo successivo. Si noti che il secondo codice è basato sulla risposta di Johan De Schutter.

Problemi correlati