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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25758782/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 08:37:54  来源:igfitidea点击:

Fire Button's onAction with Enter in JavaFX

javaeventsbuttonjavafxaction

提问by Thusitha Thilina Dayaratne

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 press Enter on button. 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.

我是 JavaFx 的新手。在我的 JavaFX 应用程序中,我设置了 onAction 属性,当我使用鼠标按下按钮时它工作正常。即使用户按 Enter 按钮,我也想触发相同的操作。我知道我可以使用偶数处理程序来做到这一点。但是当我阅读 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. Is it error in documentation? Are there any other way to achieve that without adding alistener to the button?

但是当我按下 Enter 键时,什么也没有发生。它是文档中的错误吗?有没有其他方法可以在不向按钮添加监听器的情况下实现这一目标?

P.S

聚苯乙烯

After the comments I checked with space key then it get fired. But I want to set that to Enter key. I have many buttons. I tried 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?

在评论之后我用空格键检查然后它被解雇了。但我想将其设置为 Enter 键。我有很多按钮。我试过了,button.setDefaultButton(true);但它没有被解雇。我认为这是因为有不止一个按钮。如果我仅将其设置为单个按钮,则它可以正常工作。如何将其设置为多个按钮?

采纳答案by Uluk Biy

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

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

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

回答by Qw3ry

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.

如果您想将此应用于程序中的每个 Button,您可以将 JavaFX-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作为描述在这里

回答by tomorrow

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:

要覆盖 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. 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.

基于事件的目标,该函数的工作方式如下。对于 TextArea 或 TableView,它是一个 NoOp。对于按钮,它使用 Enter 按下事件并触发 Space 键按下和释放事件。对于所有其他控件,它还会消耗 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; thanks for the comment, Robert -----

----- 编辑,因为我忘记包含 isAncestorNodeTargeted() 函数;感谢您的评论,罗伯特 -----

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