首页 > 解决方案 > 事件处理程序中的 JavaFX 设置加速器不起作用?

问题描述

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


所以这里是:我有一个包含一个按钮的 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表示已设置相应的加速器,控制台打印输出确认了这一点。但是由于某种原因,加速器没有响应我的按键。

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

标签: javadebuggingjavafxevent-handling

解决方案


推荐阅读