如何修改swing JMenu项目中的快捷键/热键“description”?

时间:2009-11-05 22:26:40

标签: java swing jmenubar

我们的swing应用程序使用“空格键”作为快捷键。换句话说,如果您在应用程序窗口中的任何位置按空格键,它将执行某种行为。更重要的是,也可以通过在窗口的菜单栏中使用JMenuItem来执行相同的行为。

实现这一点的常规方法是简单地将“spacebar”设置为相应JMenuItem的“ACCELERATOR_KEY”,然后让swing来处理其余的事情。遗憾的是,我们无法做到这一点,因为如果我们将“空格键”设置为ACCELERATOR_KEY,则每次用户点击空格键时都会触发快捷方式,即使在错误的时候也是如此,例如当用户在应用程序窗口内的文本字段中键入常规文本时

为了解决这个问题,我们已经将空格键实现为窗口级伪快捷键,而没有将其作为ACCELERATOR-KEY正确安装在相应的JMenuItem中。它工作正常,当然 JMenuItem上没有任何快捷键“提示”。也就是说,菜单项应该在菜单项上用小灰色字母表示“空格键”,这样我们的用户就可以“发现”快捷键而无需阅读用户手册。

但是文本丢失了,因为当您将快捷方式安装为ACCELERATOR-KEY时,它只会被添加到菜单项中。

所以我的问题是:如何修改JMenuItem上的快捷键提示文本,以便我可以自己添加相应的“提示”?如果我能做到这一点而不必在Look-and-Feel级别处理,那将是很好的,因为我们的应用程序是多平台并且使用了几种不同的LAFS。

4 个答案:

答案 0 :(得分:1)

感谢您的建议,伙计们。这个讨论让我得到了几个不同的解决方案。

首先,解决显示快捷方式“提示”文本的问题,而不实际有一个工作快捷键。只需将快捷键正常添加到Action / JMenuItem(这将为您提供提示文本),然后在添加快捷键后立即取消绑定。一个简单(但不是唯一)的方法是创建一个JMenuItem的子类,并覆盖一个方法:

   @Override public void setAccelerator( KeyStroke keyStroke ) {
      super.setAccelerator( keyStroke );
      getInputMap( WHEN_IN_FOCUSED_WINDOW ).put( keyStroke, "none" );
   }

瞧!一个非功能性快捷键,菜单项上的提示文本仍然完好无损。


然而,更好地解决原始问题的方法是更改​​所有快捷键的行为,以便在键盘焦点位于文本组件内时不会触发。尽我所能告诉,这实际上是唯一一种像SPACE这样的(未修改的)快捷键会与现有窗口组件的行为发生冲突的情况。第二个解决方案需要更多努力,但它更好,因为它允许我删除所有其他自定义代码以处理快捷键,而无需将其安装在JMenuBar中。

相反,我只需要在swing中使用常规快捷键架构(即将其安装在JMenuBar或Action对象中),只需进行一次小修改:

这部分再次出现在JMenuItem的自定义子类中:

   /** {@inheritDoc} */
   @Override public void setAccelerator( KeyStroke keyStroke ) {
      super.setAccelerator( keyStroke );
      if ( doClickAction_ == null ) {
         doClickAction_ = new DoClickAction( getActionMap().get( "doClick" ) );
         getActionMap().put("doClick", doClickAction_);
      }
   }

这是我的JMenuItem子类中的一个新的私有内部类:

   /**
    * This action wraps the original "doClick" action for this menu item,
    * altering it so that it only fires if the keyboard focus is not in any
    * kind of text area or text field.
    * 

* This allows accelerator keys to be added to {@link IMenuItem}s, * but the user can still type those keys into text components without * triggering the accelerator key behaviour. */ private static class DoClickAction extends AbstractAction { // the original action, i.e. that we are wrapping private final Action doClickAction_; DoClickAction( Action doClickAction ) { if ( doClickAction == null ) { throw new IllegalArgumentException(); } doClickAction_ = doClickAction; } @Override public void actionPerformed( ActionEvent e ) { final KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); if ( kfm.getFocusOwner() instanceof JTextComponent == false ) { doClickAction_.actionPerformed( e ); } } }

答案 1 :(得分:0)

考虑到您不要触及L& F代码的要求,这是加速器文本的布局......

查看JMenuItem的代码,似乎您可以为“空格键”项创建JMenutItem的子类,它将覆盖setAccelerator方法以指定加速键keyStroke ,但没有经过动作的配置。这应该允许UI代码按照您的喜好布置菜单,而不会在用户实际尝试在他们的单词之间插入空格时触发令人讨厌的操作(他们真的需要这样做吗?) 。

答案 2 :(得分:0)

我不知道文本组件是否是导致问题的唯一组件。如果是这样,那么也许您可以自定义Action以使用KeyboardFocusManager来确定当前具有焦点的组件。如果它是文本组件,那么您不会调用您的操作。

答案 3 :(得分:0)

设置加速器是否会干扰您当前实施的方式?如果没有,你可以将加速器设置到空格键......我将继续并假设你不能这样做。您可以做的另一件事是覆盖JMenuItem上的getAccelerator(),因此您不必从JMenuItem复制大部分代码(而不是那里有很多代码)。

JMenuItem clickSpace = new JMenuItem("Item With Accelerator Hint -->") {
        @Override
        public KeyStroke getAccelerator()
        {
            return KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0);
        }
    }