简体   繁体   English

在 JavaFX 中使用 Enter 触发按钮的 onAction

[英]Fire Button's onAction with Enter in JavaFX

I'm a newbie to JavaFx.我是 JavaFx 的新手。 In my JavaFX application I have set onAction property and it works fine when I press the button using mouse.在我的 JavaFX 应用程序中,我设置了 onAction 属性,当我使用鼠标按下按钮时它工作正常。 I want to fire the same even when user press Enter on button.即使用户按 Enter 按钮,我也想触发相同的操作。 I know I can use a even handler to do that.我知道我可以使用偶数处理程序来做到这一点。 But when I read the onAction JavaDoc it says that this event get fire by a key press.但是当我阅读 onAction JavaDoc 时,它说这个事件通过按键触发。

Property description:物业说明:

The button's action, which is invoked whenever the button is fired.按钮的动作,只要按钮被触发就会调用。 This may be due to the user clicking on the button with the mouse, or by a touch event, or by a key press , or if the developer programmatically invokes the fire() method.这可能是由于用户使用鼠标单击按钮、触摸事件或按键,或者开发人员以编程方式调用了 fire() 方法。

But when I press Enter key nothing happens.但是当我按下 Enter 键时,什么也没有发生。 Is it error in documentation?是文档错误吗? Are there any other way to achieve that without adding alistener to the button?有没有其他方法可以在不向按钮添加监听器的情况下实现这一目标?

PS聚苯乙烯

After the comments I checked with space key then it get fired.在评论之后我用空格键检查然后它被解雇了。 But I want to set that to Enter key.但我想将其设置为 Enter 键。 I have many buttons.我有很多按钮。 I tried button.setDefaultButton(true);我试过button.setDefaultButton(true); but it is not get fired.但它不会被解雇。 I think that is becacuse there are more than one button.我认为这是因为有不止一个按钮。 If I set it just to a single button it works fine.如果我仅将其设置为单个按钮,则它可以正常工作。 How to set that to multiple buttons?如何将其设置为多个按钮?

您可以使用绑定动态更改当前聚焦按钮的默认按钮属性

btn.defaultButtonProperty().bind(btn.focusedProperty());

If you want to apply this to every Button in your program you can subclass the JavaFX-Button and bind this in the constructor.如果您想将此应用于程序中的每个 Button,您可以将 JavaFX-Button 子类化并在构造函数中绑定它。 In your fxml-File you'll need to include your custom Button.在您的 fxml 文件中,您需要包含您的自定义按钮。

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:要使用此代码,您需要在 fxml 文件中包含您的自定义类:

<?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如果你想使用场景生成器事情变得更加困难一点:你需要导出一个jar文件的自定义按钮,添加这场景Builder作为描述在这里

To override the Enter key press behavior I use the function below calling it in the scene's key press event filter:要覆盖 Enter 按键行为,我使用下面的函数在场景的按键事件过滤器中调用它:

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.对于 TextArea 或 TableView,它是一个 NoOp。 For a button, it consumes the Enter press event and fires Space key press and release events.对于按钮,它使用 Enter 按下事件并触发 Space 键按下和释放事件。 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.对于所有其他控件,它还会消耗 Enter 按下事件并触发 Tab 事件,因此按下 Enter 会将焦点移动到下一个控件,就像 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; ----- 编辑,因为我忘记包含 isAncestorNodeTargeted() 函数; 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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM