How to consume a TAB/Enter KeyPressed on the TextArea, and replace with focustraversal or enter key without using internal API?

試著忘記壹切 提交于 2019-12-20 04:38:27

问题


I need to have a control which will wordwrap, add scrollbars, etc - but ignore the enter key and jump to the next control using tab/shift tab. I can't seem to get this right.

This is the control I have done, and it seems to just simply stay in the text area. (This was used from an old example online and it seems to work only if the textArea is in the same node as the rest).

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

Once I land in my field, it won't leave with the keyboard. Any ideas? Also - I shouldn't assume that the next control is actually in the nodes within my parent, as the control may be part of another control where its the last control and the next one might be on the parent above.

Basically I want the next landable item in the scenegraph.

I am able to do it with internal API - but I know that is very discouraged.

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

}

Thanks


回答1:


I think I found a solution which will allow me to have this work as designed.

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

If you see anything wrong with this approach I would appreciate it, but it seems to work for my purposes.



来源:https://stackoverflow.com/questions/40731195/how-to-consume-a-tab-enter-keypressed-on-the-textarea-and-replace-with-focustra

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!