2016-11-21 8 views
1

Мне нужно иметь элемент управления, который будет wordwrap, добавлять полосы прокрутки и т. Д., Но игнорировать клавишу ввода и перейти к следующему элементу управления с помощью вкладки/сдвига. Кажется, я не прав.Как использовать TAB/Enter KeyPressed в TextArea и заменять на Focustraversal или вводить ключ без использования внутреннего API?

Это контроль, который я сделал, и он просто просто остается в текстовой области. (Это использовалось из старого примера в Интернете и, похоже, работает только в том случае, если textArea находится в том же узле, что и остальные).

public class TabAndEnterIgnoringTextArea extends TextArea { 

final TextArea myTextArea = this; 

public TabAndEnterIgnoringTextArea() { 
    this.setWrapText(true); 
    addEventFilter(KeyEvent.KEY_PRESSED, new TabAndEnterHandler()); 
} 

private class TabAndEnterHandler implements EventHandler<KeyEvent> { 
    private KeyEvent recodedEvent; 

    @Override 
    public void handle(KeyEvent event) { 
     if (recodedEvent != null) { 
      recodedEvent = null; 
      return; 
     } 


     Parent parent = getParent(); 
     if (parent != null) { 
      switch (event.getCode()) { 
      case ENTER: 
       if (event.isControlDown()) { 
        recodedEvent = recodeWithoutControlDown(event); 
        myTextArea.fireEvent(recodedEvent); 
       } else { 
        Event parentEvent = event.copyFor(parent, parent); 
        myTextArea.getParent().fireEvent(parentEvent); 
       } 
       event.consume(); 
       break; 

      case TAB: 
       if (event.isControlDown()) { 
        recodedEvent = recodeWithoutControlDown(event); 
        myTextArea.fireEvent(recodedEvent); 
       } else if (event.isShiftDown()) { 
        ObservableList<Node> children = FXCollections.observableArrayList(); 
        addAllDescendents(parent, children); 
        int idx = children.indexOf(myTextArea); 
        if (idx > 0) { 
         for (int i = idx - 1; i > 0; i--) { 
          if (children.get(i).isFocusTraversable()) { 
           children.get(i).requestFocus(); 
           break; 
          } 
         } 
        } 
       } else { 
        ObservableList<Node> children = FXCollections.observableArrayList(); 
        addAllDescendents(parent, children); 
        int idx = children.indexOf(myTextArea); 
        if (idx >= 0) { 
         for (int i = idx + 1; i < children.size(); i++) { 
          if (children.get(i).isFocusTraversable()) { 
           children.get(i).requestFocus(); 
           break; 
          } 
         } 
         if (idx + 1 >= children.size()) { 
          for (int i = 0; i < idx; i++) { 
           if (children.get(i).isFocusTraversable()) { 
            children.get(i).requestFocus(); 
            break; 
           } 
          } 
         } 
        } 
       } 
       event.consume(); 
       break; 
      default: 
       break; 
      } 
     } 
    } 

    private void addAllDescendents(Parent parent, ObservableList<Node> nodes) { 
     for (Node node : parent.getChildrenUnmodifiable()) { 
      nodes.add(node); 
      if (node instanceof Parent) 
       addAllDescendents((Parent) node, nodes); 
     } 
    } 

    private KeyEvent recodeWithoutControlDown(KeyEvent event) { 
     return new KeyEvent(event.getEventType(), event.getCharacter(), event.getText(), event.getCode(), 
       event.isShiftDown(), false, event.isAltDown(), event.isMetaDown()); 
    } 
} 

Как только я приземлюсь в своем поле, он не уйдет с клавиатуры. Есть идеи? Кроме того, я не должен предполагать, что следующий элемент управления фактически находится в узлах моего родителя, поскольку элемент управления может быть частью другого элемента управления, где его последний элемент управления и следующий могут быть на родительском элементе выше.

В принципе, я хочу следующий доступный предмет на сценографе.

Я могу сделать это с помощью внутреннего API, но я знаю, что это очень обескураживает.

public class TabAndEnterIgnoringTextArea extends TextArea { 

final TextArea myTextArea = this; 

public TabAndEnterIgnoringTextArea() { 
    addEventFilter(KeyEvent.KEY_PRESSED, new TabAndEnterHandler()); 
} 

class TabAndEnterHandler implements EventHandler<KeyEvent> { 
    private KeyEvent recodedEvent; 

    @Override 
    public void handle(KeyEvent event) { 
     if (recodedEvent != null) { 
      recodedEvent = null; 
      return; 
     } 

     Parent parent = myTextArea.getParent(); 
     Scene scene = parent.getScene(); 
     while (scene == null){ 
      parent = parent.getParent(); 
      scene = parent.getScene(); 
     } 
     SceneTraversalEngine engine = new SceneTraversalEngine(getScene()); 

     if (parent != null) { 
      switch (event.getCode()) { 
      case ENTER: 
       if (event.isControlDown()) { 
        recodedEvent = recodeWithoutControlDown(event); 
        myTextArea.fireEvent(recodedEvent); 
       } else { 
        Event parentEvent = event.copyFor(parent, parent); 
        myTextArea.getParent().fireEvent(parentEvent); 
       } 
       event.consume(); 
       break; 

      case TAB: 
       if(event.isShiftDown()){ 
        engine.trav(myTextArea, Direction.PREVIOUS); 
       }else { 
        engine.trav(myTextArea, Direction.NEXT); 
       } 
      } 
     } 
    } 

    private KeyEvent recodeWithoutControlDown(KeyEvent event) { 
     return new KeyEvent(event.getEventType(), event.getCharacter(), event.getText(), event.getCode(), 
       event.isShiftDown(), false, event.isAltDown(), event.isMetaDown()); 
    } 
} 

}

Благодаря

ответ

1

Я думаю, я нашел решение, которое позволит мне иметь эту работу, как задумано.

public class TabAndEnterIgnoringTextArea extends TextArea { 

final TextArea myTextArea = this; 

public TabAndEnterIgnoringTextArea() { 
    this.setWrapText(true); 
    addEventFilter(KeyEvent.KEY_PRESSED, new TabAndEnterHandler()); 
} 

private class TabAndEnterHandler implements EventHandler<KeyEvent> { 
    @Override 
    public void handle(KeyEvent event) { 
     if(event.getCode() == KeyCode.TAB || event.getCode() == KeyCode.ENTER) { 
      event.consume(); 
      if(event.getCode() == KeyCode.TAB){ 
       selectNextNode(!event.isShiftDown()); 
      } 
     } 
    } 

    private void selectNextNode(boolean forward){ 
     List<Node> nodes = getAllNodes(myTextArea.getScene().getRoot()); 
     int index = nodes.indexOf(myTextArea); 
     if(forward){ 
      if(index < nodes.size() - 1) { 
       nodes.get(index + 1).requestFocus(); 
      }else { 
       nodes.get(0).requestFocus(); 
      } 
     }else { 
      if(index == 0) { 
       nodes.get(nodes.size() - 1).requestFocus(); 
      }else { 
       nodes.get(index - 1).requestFocus(); 
      } 
     } 
    } 

    private ArrayList<Node> getAllNodes(Parent root) { 
     ArrayList<Node> nodes = new ArrayList<Node>(); 
     addAllDescendents(root, nodes); 
     return nodes; 
    } 

    private void addAllDescendents(Parent parent, ArrayList<Node> nodes) { 
     for (Node node : parent.getChildrenUnmodifiable()) { 
      if(node.isFocusTraversable()){ 
       nodes.add(node); 
      } 
      if (node instanceof Parent) 
       addAllDescendents((Parent)node, nodes); 
     } 
    } 
} 
} 

Если вы видите что-то не так с этим подходом, я был бы признателен, но, похоже, это работает для моих целей.

+0

Фильтр событий - фильтрует событие до его попадания в узел. Это верно? В этом случае с textarea он не фильтрует сцену, другие узлы и сцену. Правильно? – Lealo

+1

Это правильно, если вы поместили фильтр на узел. –