3

我们的应用程序使用带有单个 Stage 的 JavaFX 用户界面,其中包含顶部的 MenuBar,以及下方的许多其他控件。

我们想使用 KeyCode.SPACE(即空格键)作为我们的 MenuBar 中的一个 MenuItems 的加速器。是的,我知道这不是用于菜单加速器的理想键。这不是我的决定。:)

总之,起初 SPACE 加速器运行良好:

menuItem.setAccelerator( KeyCombination.valueOf( "SPACE" ) );

但是当我们开始将 TableView 等其他控件添加到我们的舞台时,该加速器停止工作。事实证明,那些其他控件将 SPACE 用于自己的目的,并在 KeyEvent 返回到 MenuBar 之前使用它。

因此,我们决定不需要 SPACE 来处理其他控件,因此我通过使用事件过滤器“解决”了这个问题。它在获得其他控件之前为我的 MenuItem 窃取了 SPACE KeyEvent:

stage.addEventFilter( KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
  public void handle( KeyEvent e ) {
     if ( e.getCode() == KeyCode.SPACE &&
        !(e.getTarget() instanceof TextInputControl) && 
        !menuItem.isDisable() ) {
           e.consume();
           menuItem.fire();
     }
  }
});

这似乎可行,但我希望可能有一个更清洁、更不脆弱的解决方案。特别是,我真的很想找到一种方法来告诉其他控件(如 TableView)停止使用 SPACE KeyEvent。

这可能吗?

4

1 回答 1

1

我有一个类似的问题,一些控件,特别是文本输入控件,使用定义为菜单加速器的功能键。为了解决这个问题,我找到了一种更通用的方法来使菜单加速器优先于控件的键消耗:

control.addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
    @Override
    public void handle(KeyEvent event) {
        Scene scene = control.getScene();
        if (scene == null) {
            return;
        }
        Map<KeyCombination,Runnable> accelerators = scene.getAccelerators();
        for (KeyCombination keyCombination : accelerators.keySet()) {
            if (keyCombination.match(event)) {
                accelerators.get(keyCombination).run();
                event.consume();
                return;
            }
        }
    }
});

这比问题中提出的解决方案要脆弱一些,因为它不会将键硬编码到事件过滤器中,并且它允许所有菜单项处理由来自的 Runnables 完成Scene.getAccelerators()。这些 Runnable 是在实现类com.sun.javafx.scene.control.ControlAcceleratorSupport中定义的 method doAcceleratorInstall

我更喜欢将此过滤器添加到每个违规控件,但它当然也可以安装在舞台上。

于 2015-10-11T19:40:20.950 回答