在 JavaFX 中关闭时未消耗 Dialog 上的 KeyEvent

KeyEvent on Dialog not consumed when closing in JavaFX

我需要在用户按下 ENTER 键时导航 table。为此,我创建了一个类似于以下内容的事件过滤器:

private EventHandler<KeyEvent> keyReleasedFilter = event -> {
    if ((event.getCode() == KeyCode.ENTER || event.getCode() == KeyCode.TAB)) {
        previousPosition = table.getFocusModel().getFocusedCell();
        //do my navigation
    }
}

我 运行 遇到一个问题,在 table 导航期间使用 JavaFX 模态对话框指示错误,导致此过滤器出现问题。如果用户使用 ENTER 键关闭对话框,则该事件将被我在父阶段的事件过滤器捕获。我不确定如何防止这种情况。它导致导航不一致。

这是一个演示行为的简单应用程序:

public void start(Stage primaryStage) {
    final Alert d = new Alert(Alert.AlertType.ERROR);
    d.initModality(Modality.WINDOW_MODAL);

    Button btn = new Button();
    btn.setText("Say 'Hello World'");
    btn.addEventFilter(KeyEvent.KEY_RELEASED, event -> {
        if ((event.getCode() == KeyCode.ENTER || event.getCode() == KeyCode.TAB)) {
            d.showAndWait();
        }
    });

    Scene scene = new Scene(new StackPane(btn), 300, 250);

    primaryStage.setTitle("Hello World!");
    primaryStage.setScene(scene);
    primaryStage.show();
}

我注意到对话框随 KEY_PRESSED 事件关闭,不会捕获 KEY_RELEASED 事件。

我已经尝试将事件过滤器添加到对话框(Button/DialogPane/Scene 甚至舞台)- none 拦截 KEY_RELEASED 事件。

谢谢。

所以我有一个有效的 hack - 我真的不喜欢它,所以我希望有一个更好的解决方案(一个干净的解决方案)来解决这个问题....

基本上,在我打开我的对话框之前,我设置了一个布尔值,所以我知道它是打开的。然后在我的事件过滤器中,如果设置为 true,则踢出。

public class EventTester 扩展应用程序{

public static void main(String[] args){
    launch(args);
}

private boolean modalWasShowing = false;
@Override
public void start(Stage primaryStage) {
    final Alert d = new Alert(Alert.AlertType.ERROR);
    d.initModality(Modality.WINDOW_MODAL);

    Button btn = new Button();
    btn.setText("Say 'Hello World'");
    btn.addEventFilter(KeyEvent.KEY_RELEASED, event -> {
        if(modalWasShowing){
            modalWasShowing=false;
            return;
        }
        if ((event.getCode() == KeyCode.ENTER || event.getCode() == KeyCode.TAB)) {
            modalWasShowing = true;
            d.showAndWait();
        }
    });

    Scene scene = new Scene(new StackPane(btn), 300, 250);

    primaryStage.setTitle("Hello World!");
    primaryStage.setScene(scene);
    primaryStage.show();
}

如果您知道更好的处理方法,请告诉我。

除非有其他原因使用 KEY_RELEASED 事件,否则我建议切换到 KEY_PRESSED 触发以进行导航,并将 EventFilter 切换到 EventHandler.下面的示例将允许您打开和关闭 Alert。当它打开时,您会注意到按钮文本没有改变。当它关闭时,按钮文本将改变。看看 JavaFX 如何构建事件链 here 如果您还没有看过的话。

boolean error = false;
int i = 0;

@Override
public void start(Stage primaryStage)
{
    final Alert d = new Alert(Alert.AlertType.ERROR);
    d.initModality(Modality.WINDOW_MODAL);

    Button err = new Button();
    err.setText("Error off");
    err.addEventHandler(ActionEvent.ACTION, t ->
    {
        error = !error;
        if (error)
            err.setText("Error on");
        else
            err.setText("Error off");
    });

    Button btn = new Button();
    btn.setText("Say 'Hello World'");

    btn.addEventHandler(KeyEvent.KEY_PRESSED, event ->
    {
        if ((event.getCode() == KeyCode.ENTER || event.getCode() == KeyCode.TAB)) {
            if (error)
            {
                d.showAndWait();
            }
            else
            {
                i++;
                btn.setText(String.valueOf(i));
            }
        }
    });


    Scene scene = new Scene(new VBox(btn, err), 300, 250);

    primaryStage.setTitle("Hello World!");
    primaryStage.setScene(scene);
    primaryStage.show();
}