2

我们的 Swing 应用程序使用“空格键”作为快捷键。换句话说,如果您在应用程序窗口中的任意位置按下空格键,它将执行某种行为。此外,同样的行为也可以通过在窗口的菜单栏中使用 JMenuItem 来执行。

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

为了解决这个问题,我们将空格键实现为窗口级伪快捷键,但没有将其作为加速键正确安装在相应的 JMenuItem 中。它工作正常,当然JMenuItem 上没有任何快捷键“提示”。也就是说,菜单项应该在菜单项的正上方用灰色的小字写出“空格键”,这样我们的用户就可以在不阅读用户手册的情况下“发现”快捷键。

但是文本丢失了,因为它仅在您将快捷方式安装为加速键时才添加到菜单项中。

所以我的问题是: 如何修改 JMenuItem 上的快捷键提示文本,以便我自己添加适当的“提示”?如果我能做到这一点而不必在外观级别上搞砸,那就太好了,因为我们的应用程序是多平台的,并且使用了几个不同的 LAFS。

4

4 回答 4

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 子类中的一个新的私有内部类:

   /**
    * 这个动作包装了这个菜单项的原始“doClick”动作,
    * 修改它,使其仅在键盘焦点不在任何位置时触发
    * 文本区域或文本字段的种类。
    *

* 这允许将加速键添加到 {@link IMenuItem}s, * 但用户仍然可以将这些键输入到文本组件中,而无需 * 触发加速键行为。 */ 私有静态类 DoClickAction 扩展 AbstractAction { // 原始动作,即我们正在包装 私人最终动作 doClickAction_; DoClickAction( 动作 doClickAction ) { 如果(doClickAction == null){ 抛出新的 IllegalArgumentException(); } doClickAction_ = doClickAction; } @Override public void actionPerformed(ActionEvent e) { 最终的 KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); if ( kfm.getFocusOwner() instanceof JTextComponent == false ) { doClickAction_.actionPerformed(e); } } }

于 2009-11-12T01:17:54.230 回答
0

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

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

于 2009-11-05T22:40:09.227 回答
0

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

于 2009-11-05T23:56:59.103 回答
0

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

JMenuItem clickSpace = new JMenuItem("Item With Accelerator Hint -->") {
        @Override
        public KeyStroke getAccelerator()
        {
            return KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0);
        }
    }
于 2009-11-10T17:12:16.683 回答