繁体   English   中英

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

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

我是 JavaFx 的新手。 在我的 JavaFX 应用程序中,我设置了 onAction 属性,当我使用鼠标按下按钮时它工作正常。 即使用户按 Enter 按钮,我也想触发相同的操作。 我知道我可以使用偶数处理程序来做到这一点。 但是当我阅读 onAction JavaDoc 时,它说这个事件通过按键触发。

物业说明:

按钮的动作,只要按钮被触发就会调用。 这可能是由于用户使用鼠标单击按钮、触摸事件或按键,或者开发人员以编程方式调用了 fire() 方法。

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

聚苯乙烯

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

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

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

如果您想将此应用于程序中的每个 Button,您可以将 JavaFX-Button 子类化并在构造函数中绑定它。 在您的 fxml 文件中,您需要包含您的自定义按钮。

我写了以下子类:

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

}

要使用此代码,您需要在 fxml 文件中包含您的自定义类:

<?import your-package.*?>

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

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

基于事件的目标,该函数的工作方式如下。 对于 TextArea 或 TableView,它是一个 NoOp。 对于按钮,它使用 Enter 按下事件并触发 Space 键按下和释放事件。 对于所有其他控件,它还会消耗 Enter 按下事件并触发 Tab 事件,因此按下 Enter 会将焦点移动到下一个控件,就像 Tab 一样。

然后你只需为整个场景注册一个事件过滤器:

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

事件过滤器看起来像:

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

----- 编辑,因为我忘记包含 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;
}

暂无
暂无

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

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