2012-10-12 19 views
12

Làm cách nào để tôi nhấn phím Tab trong TextArea điều hướng đến điều khiển tiếp theo?Điều hướng phím Tab trong JavaFX TextArea

Tôi có thể thêm người nghe vào sự kiện nhấn phím cath de, nhưng làm cách nào để kiểm soát te TextArea mất tập trung (mà không biết trường tiếp theo trong chuỗi cần tập trung)?

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

Trả lời

8

Mã này Traverse tập trung nếu nhấn TAB và tab chèn nếu nhấn 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

Một vấn đề nhỏ: cần có dấu kiểm cho event.isShiftDown() sẽ gọi là "TraversePrevious", không phải là "TraverseNext". –

+4

Ít nhất đối với JavaFX 8, SkinBase nên được thay đổi thành TextAreaSkin. – tunabot

12

tôi sử dụng traverse-phương pháp

@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

Giải pháp này là giải pháp sạch nhất tôi tìm thấy. Mặc dù không cần thiết phải định nghĩa nó cho TextFields, vì đây là một mặc định (ít nhất là trong Java 8). – codepleb

+0

Vấn đề là, nó buộc bạn phải mở rộng TextArea - không phải rất thuận tiện nếu bạn sử dụng Trình tạo cảnh. – User

+0

... thực sự @Override đã ném tôi ra, không có phương pháp xử lý để ghi đè trong một TextArea, vì vậy tôi đoán đây chỉ là một phương pháp xử lý thông thường. Tuy nhiên, tôi ước có một cách dễ dàng hơn - tốt thôi. – User

0

tôi đã cùng một vấn đề và tôi thích các phương thức đi ngang mà Tom sử dụng. Nhưng tôi cũng muốn chèn một tab khi nhấn ctrl + tab.

Cuộc gọi

behavior.callAction("InsertTab"); 

doesn't làm việc với JavaFX8. Một cái nhìn trong lớp TextAreaBehaviour cho tôi thấy rằng bây giờ có một hành động "TraverseOrInsertTab".

Nhưng tuy nhiên, tôi cho rằng kiểu gọi hành động này khá không ổn định trên nhiều phiên bản java vì nó dựa trên chuỗi được chuyển.

Vì vậy, thay vì phương pháp callAction(), tôi sử dụng

textArea.replaceSelection("\t"); 
1

Nếu một giải pháp khác nhau cho các Tab - vấn đề Focus. Hành vi mặc định của TextArea cho phím CTRL + TAB là di chuyển tiêu điểm đến điều khiển tiếp theo. Vì vậy, tôi đã thay thế sự kiện khóa TAB bằng sự kiện khóa CTRL + TAB và khi người dùng nhấn CTRL + TAB, một ký tự tab được chèn vào TextArea.

Câu hỏi của tôi: OK để kích hoạt sự kiện trong bộ lọc sự kiện? Và có thể thay thế văn bản của KeyEvent bằng FOCUS_EVENT_TEXT, để có chỉ báo nếu đó là sự kiện do người dùng tạo hoặc từ sự kiện được tạo trong bộ lọc sự kiện.

Bộ lọc sự kiện:

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

Các xử lý sự kiện:

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

Lấy cảm hứng từ câu trả lời trước và trong một trường hợp rất giống nhau, tôi đã xây dựng các lớp sau đây:

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

Tôi chưa thấy sự cần thiết của h andling tab trong bối cảnh của một TextField vì vậy tôi loại bỏ phần này.

Sau đó, lớp này có thể rất dễ dàng sử dụng như mô tả của User:

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

Và toàn bộ điều hoạt động giống như một nét duyên dáng :)

2

Tính đến Java 9 (2017), hầu hết các câu trả lời trong trang này không hoạt động, vì bạn không thể làm được skin.getBehavior() nữa.

này hoạt động:

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

này cũng hoạt động:

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

Cả hai mô phỏng cách nhấn CTRL+TAB khi người dùng nhấn TAB. Hành vi mặc định của TextArea cho CTRL+TAB là di chuyển tiêu điểm đến điều khiển tiếp theo. Xin lưu ý mã thứ hai dựa trên câu trả lời của Johan De Schutter.