2012-10-12 50 views
12

如何使TextArea中的Tab鍵導航到下一個控件?JavaFX中的Tab鍵導航TextArea

我可以添加一個監聽器給cath按鍵按下的事件,但是如何讓te TextArea控件失去焦點(不知道鏈中下一個要被聚焦的區域)?

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

回答

8

如果按下Control + TAB此代碼遍歷集中,如果按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

一個小問題:它應該檢查event.isShiftDown(),它應該調用「TraversePrevious」,而不是「TraverseNext」。 –

+4

至少對於JavaFX 8,SkinBase應該更改爲TextAreaSkin。 – tunabot

12

我用的是橫向的方法

@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

這個解決方案是我找到的最乾淨的。雖然沒有必要爲TextFields定義它,因爲這已經是默認的(至少在Java 8中)。 – codepleb

+0

雖然問題是,它迫使你擴展TextArea - 如果你使用Scene Builder不是很方便。 – User

+0

...其實@Override把我扔了,沒有處理方法在TextArea中重寫,所以我想這只是一個常規處理程序方法。不過,我希望有一個更簡單的方法 - 哦,好吧。 – User

0

我有同樣的問題,我喜歡Tom使用的遍歷方法。 但我也想按Ctrl + Tab時插入一個選項卡。

呼叫

behavior.callAction("InsertTab"); 

doesn't工作,JavaFX8。 TextAreaBehaviour類的外觀讓我知道現在有一個「TraverseOrInsertTab」操作。

但是,我認爲這種動作調用在幾個Java版本中相當不穩定,因爲它依賴於傳遞的字符串。

因此,而不是在callAction()方法中,我使用

textArea.replaceSelection("\t"); 
1

如果用於標籤不同的解決方案 - 焦點問題。 CTRL + TAB鍵的TextArea的默認行爲是焦點移動到下一個控件。因此,我用CTRL + TAB鍵事件替換了TAB鍵事件,並且當用戶點擊CTRL + TAB時,在TextArea中插入了製表符。

我的問題:可以在事件過濾器中觸發事件嗎?可以用FOCUS_EVENT_TEXT替換KeyEvent的文本,以便指示它是用戶生成的事件還是事件過濾器中創建的事件。

事件過濾器:

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

的事件處理程序:

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

由以前的答案和一個非常類似的事例的啓發,我建立了下面的類:

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

我只是沒有看到h的必要性在TextField的上下文中,我刪除了這部分。

然後可以通過User描述可以非常容易地使用這個類:

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

而且整個事情就像一個魅力:)

2

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

兩個模擬按下CTRL+TAB當用戶按下TAB。 TextArea的默認行爲CTRL+TAB正在將焦點移到下一個控件。請注意第二個代碼是基於Johan De Schutter的回答。