事件处理程序中的JavaFX Set Accelerator不起作用?

时间:2018-06-19 09:44:17

标签: java debugging javafx event-handling

为漫长的背景故事道歉。但我认为你有必要了解我的意图并理解这个错误。

所以这就是:我有一个包含按钮的JavaFX GUI。我的意图是通过右键单击按钮,用户可以调出上下文菜单,此时他们可以使用单个按键来触发菜单项。所以我这是我的start()方法:

    FlowPane root = new FlowPane();
    Scene scene = new Scene(root, 300, 100);

    Button btn = new Button("Test");

    // Add context menu and define actions.
    ContextMenu cM = new ContextMenu();

    MenuItem mI0 = new MenuItem("First");
    mI0.setOnAction(aE ->
    {
        System.out.println("First Action");
        cM.hide();
    });
    MenuItem mI1 = new MenuItem("Second");
    mI1.setOnAction(aE ->
    {
        System.out.println("Second Action");
        cM.hide();
    });
    cM.getItems().addAll(mI0, mI1);

    // Set accelerators.
    mI0.setAccelerator(new KeyCodeCombination(KeyCode.F));
    mI1.setAccelerator(new KeyCodeCombination(KeyCode.S));

    btn.setContextMenu(cM);

    root.getChildren.add(btn);

    primaryStage.setScene(scene);
    primaryStage.show();

这很好用。我可以右键单击按钮,键入fs,然后打印相应的文本。一切都很好。

但是在我的GUI中,我实际上有几个按钮,每个按钮代表一个可执行文件,并有自己的上下文菜单。上下文菜单中的项目是"运行"和"使用参数"运行,并触发它们应该运行该特定的可执行文件。所以我的代码变成了这个。为了简单起见,我使用水果作为类比。

    FlowPane root = new FlowPane();
    Scene scene = new Scene(root, 300, 100);

    String[] buttonNames = { "Apple", "Pear", "Orange" };
    for (String s : buttonNames)
    {
        Button btn = new Button(s);

        // Add context menu and define actions.
        ContextMenu cM = new ContextMenu();

        MenuItem mI0 = new MenuItem("Eat");
        mI0.setOnAction(aE ->
        {
            System.out.println("Eat " + btn.getText());
            cM.hide();
        });
        MenuItem mI1 = new MenuItem("Cut");
        mI1.setOnAction(aE ->
        {
            System.out.println("Cut " + btn.getText());
            cM.hide();
        });
        cM.getItems().addAll(mI0, mI1);

        // Set accelerators.
        mI0.setAccelerator(new KeyCodeCombination(KeyCode.E));
        mI1.setAccelerator(new KeyCodeCombination(KeyCode.C));

        btn.setContextMenu(cM);

        root.getChildren().add(btn);
    }

    primaryStage.setScene(scene);
    primaryStage.show();

现在,如果你保持警惕,你可能马上就注意到了这个问题。加速器是为场景设置的,因此即使上下文菜单未显示,也可以在键盘触发器上按ec。更糟糕的是,现在唯一吃掉或切成的水果是橘子,因为它的加速器已经覆盖了苹果和梨的水果。

所以我对此的解决方案如下。在显示上下文菜单时设置加速器,并在隐藏时将其删除。听起来很简单。

    FlowPane root = new FlowPane();
    Scene scene = new Scene(root, 300, 100);

    String[] buttonNames = { "Apple", "Pear", "Orange" };
    for (String s : buttonNames)
    {
        Button btn = new Button(s);

        // Add context menu and define actions.
        ContextMenu cM = new ContextMenu();

        MenuItem mI0 = new MenuItem("Eat");
        mI0.setOnAction(aE ->
        {
            System.out.println("Eat " + btn.getText());
            cM.hide();
        });
        MenuItem mI1 = new MenuItem("Cut");
        mI1.setOnAction(aE ->
        {
            System.out.println("Cut " + btn.getText());
            cM.hide();
        });
        cM.getItems().addAll(mI0, mI1);

        // Set accelerator on context menu show.
        cM.setOnShown(wE ->
        {
            mI0.setAccelerator(new KeyCodeCombination(KeyCode.E));
            mI1.setAccelerator(new KeyCodeCombination(KeyCode.C));
            System.out.println("Accelerators set for " + btn.getText());
        });
        // Remove accelerator on context menu hide.
        cM.setOnHiding(wE ->
        {
            cM.getItems().forEach(mI -> mI.setAccelerator(null));
            System.out.println("Accelerators removed for " + btn.getText());
        });

        btn.setContextMenu(cM);

        root.getChildren().add(btn);
    }

    primaryStage.setScene(scene);
    primaryStage.show();

没有理由不这样做。当仅使用鼠标时,它似乎正在起作用:

但是当我在打开上下文菜单后按ec时,会发生这种情况:

(按e

什么都没发生。

现在您可以清楚地看到代码设置和删除加速器的行已经运行。菜单中EC旁边的EatCut表示已设置相应的加速器,控制台打印输出确认了这一点。但由于某种原因,加速器没有响应我的按键。

有人可以告诉我为什么以及可能如何解决这个问题?

0 个答案:

没有答案