Fire Button's onAction with Enter in JavaFX

前端 未结 3 1897
生来不讨喜
生来不讨喜 2020-12-10 13:58

I\'m a newbie to JavaFx. In my JavaFX application I have set onAction property and it works fine when I press the button using mouse. I want to fire the same even when user

相关标签:
3条回答
  • 2020-12-10 14:21

    If you want to apply this to every Button in your program you can subclass the JavaFX-Button and bind this in the constructor. In your fxml-File you'll need to include your custom Button.

    I wrote the following subclass:

    public class FocusedButton extends javafx.scene.control.Button {
    
        public FocusedButton ( ) {
            super ( );
            bindFocusToDefault ( );
        }
    
        public FocusedButton ( String text ) {
            super ( text );
            bindFocusToDefault ( );
        }
    
        public FocusedButton ( String text, Node graphic ) {
            super ( text, graphic );
            bindFocusToDefault ( );
        }
    
        private void bindFocusToDefault ( ) {
            defaultButtonProperty().bind(focusedProperty());
        }
    
    }
    

    To use this Code you will need to include your custom class in the fxml-File:

    <?import your-package.*?>
    

    If you want to use the Scene Builder things get a little bit more difficult: You'll need to export your custom Button in a jar-file and add this to Scene Builder as described here

    0 讨论(0)
  • 2020-12-10 14:30

    You can dynamically change the default button property of the currently focused button by using binding

    btn.defaultButtonProperty().bind(btn.focusedProperty());
    
    0 讨论(0)
  • 2020-12-10 14:43

    Why do I always answer three years old questions...?! ;-) Anyway, someone might find it useful (including myself).

    To override the Enter key press behavior I use the function below calling it in the scene's key press event filter:

    public static void overrideEnterKeyPressEvent(KeyEvent evt) {
        EventTarget eventTarget = evt.getTarget();
    
        if ((eventTarget instanceof TextArea) || (eventTarget instanceof TableView)) {
            return;
        }
    
        if (eventTarget instanceof Button) {
            Platform.runLater(() -> {
                KeyEvent newEventPressed = new KeyEvent(KeyEvent.KEY_PRESSED, " ", " ", KeyCode.SPACE, false, false, false, false);
                Event.fireEvent(eventTarget, newEventPressed);
                KeyEvent newEventReleased = new KeyEvent(KeyEvent.KEY_RELEASED, " ", " ", KeyCode.SPACE, false, false, false, false);
                Event.fireEvent(eventTarget, newEventReleased);
            });
            evt.consume();
            return;
        }
    
        Platform.runLater(() -> {
            KeyEvent tabEvent = new KeyEvent(KeyEvent.KEY_PRESSED, "", "\t", KeyCode.TAB, evt.isShiftDown(), false, false, false);
            Event.fireEvent(eventTarget, tabEvent);
        });
        evt.consume();
    }
    

    Based on the event's target the function works as follows. For a TextArea or TableView, it's a NoOp. For a button, it consumes the Enter press event and fires Space key press and release events. And for all the other controls, it also consumes the Enter press event and fires a Tab event so pressing Enter moves focus to the next control just like Tab.

    Then you just register an event filter for the whole scene:

        scene.addEventFilter(KeyEvent.KEY_PRESSED, this::onSceneKeyPressedFilter);
    

    And the event filter looks like:

    private void onSceneKeyPressedFilter(KeyEvent evt) {
        switch (evt.getCode()) {
            case ENTER:
                if (evt.isControlDown() && FxTools.isAncestorNodeTargeted(evt.getTarget(), fxHBoxInputAp)) {
                    return; //let the events for the fxHBoxInputAp pane pass through
                }
                overrideEnterKeyPressEvent(evt);
                break;
            ...
            default:
                break;
        }
    }
    

    ----- edit because I forgot to include the isAncestorNodeTargeted() function; thanks for the comment, Robert -----

    public static boolean isDescendantOf(Node node, Node ancestor) {
        while ((node != null) && (node != ancestor)) {
            node = node.getParent();
        }
        return (node != null);
    }
    
    
    public static boolean isAncestorNodeTargeted(EventTarget target, Node ancestor) {
        return (target instanceof Node) ? isDescendantOf((Node) target, ancestor) : false;
    }
    
    0 讨论(0)
提交回复
热议问题