文档

Java™教程
隐藏目录
如何使用按键绑定
教程:使用Swing创建GUI
课程:使用其他Swing功能

如何使用键绑定

JComponent类支持按键绑定作为响应用户按键的一种方式。以下是一些适用于按键绑定的示例:

您通常不需要直接使用按键绑定。它们在幕后由助记符(由所有按钮、选项卡窗格以及JLabel支持)和加速器(由菜单项支持)使用。您可以在启用键盘操作一节中找到助记符和加速器的相关内容。

按键绑定的替代方法是使用键盘监听器。键盘监听器作为与键盘输入的低级接口有其作用,但对于响应单个按键,按键绑定更合适且通常会导致更易于维护的代码。如果要在组件没有焦点时激活按键绑定,键盘监听器也会很困难。按键绑定的一些优点是它们在某种程度上是自文档的,考虑了包含层次结构,鼓励重用代码块(Action对象),并允许轻松删除、自定义或共享操作。此外,它们使得更改操作绑定的按键变得容易。Actions的另一个优点是它们具有一个启用状态,这提供了一种轻松禁用操作的方式,而无需跟踪它附加到的组件。

本节的其余部分将为您提供使用按键绑定所需的详细信息:

按键绑定的工作原理

JComponent提供的按键绑定支持依赖于InputMapActionMap类。输入映射将按键绑定到操作名称,而操作映射指定与每个操作名称对应的操作。从技术上讲,您不需要在映射中使用操作名称;您可以使用任何对象作为映射的“键”。但按照惯例,您使用命名操作的字符串作为“键”。

每个InputMap/ActionMap都有一个通常来自UI的父级。每次更改外观和感觉时,父级都会重置。通过这种方式,开发人员指定的绑定在外观和感觉变化时永远不会丢失。

每个JComponent有一个动作映射和三个输入映射。输入映射对应于以下焦点情况:

JComponent.WHEN_FOCUSED
组件具有键盘焦点。当组件没有子组件时,通常使用WHEN_FOCUSED输入映射。例如,按钮使用WHEN_FOCUSED映射将空格键绑定在按钮上。
这些绑定仅在组件具有焦点时有效。
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
组件包含(或是)具有焦点的组件。这个输入映射通常用于复合组件 - 一个依赖子组件实现的组件。例如,JTable使用WHEN_ANCESTOR_OF_FOCUSED_COMPONENT创建所有绑定,这样如果用户正在编辑,向上箭头键(例如)仍然会更改选定的单元格。
JComponent.WHEN_IN_FOCUSED_WINDOW
组件的窗口具有焦点或包含具有焦点的组件。这个输入映射通常用于助记键或加速键,无论焦点在窗口的哪个位置,都需要处于活动状态。

当用户键入键时,JComponent的键事件处理代码会搜索一个或多个输入映射以找到有效的绑定。当找到绑定时,它会在动作映射中查找相应的动作。如果动作已启用,则绑定有效,并执行动作。如果动作已禁用,则继续搜索有效的绑定。

如果键存在多个绑定,则只使用找到的第一个有效绑定。按照以下顺序检查输入映射:

  1. 焦点组件的WHEN_FOCUSED输入映射。
  2. 焦点组件的WHEN_ANCESTOR_OF_FOCUSED_COMPONENT输入映射。
  3. 焦点组件的父级的WHEN_ANCESTOR_OF_FOCUSED_COMPONENT输入映射,然后是父级的父级,以此类推,一直向上继续容器层次结构。注意:跳过禁用组件的输入映射。
  4. 在焦点窗口中的所有启用组件的WHEN_IN_FOCUSED_WINDOW输入映射中搜索。由于搜索组件的顺序是不可预测的,避免重复的WHEN_IN_FOCUSED_WINDOW绑定!

让我们考虑两种典型的按键绑定情况:按钮对Space键的反应以及具有默认按钮的框架对Enter键的反应。

在第一种情况下,假设用户在一个JButton具有键盘焦点时按下了Space键。首先,按钮的键监听器会收到事件的通知。假设没有任何键监听器通过调用KeyEvent上的consume方法"消耗"了事件,按钮的WHEN_FOCUSED输入映射将被咨询。找到一个绑定,因为JButton使用该输入映射将Space绑定到一个动作名称。在按钮的动作映射中查找该动作名称,并调用该动作的actionPerformed方法。KeyEvent被消耗,处理停止。

在第二种情况下,假设在具有默认按钮的框架内的任何位置按下Enter键(使用JRootPanesetDefaultButton方法设置默认按钮)。无论焦点在哪个组件上,首先通知其键盘监听器。假设没有任何监听器消耗键盘事件,则会查找焦点组件的WHEN_FOCUSED输入映射。如果该映射没有绑定键或者绑定到该键的操作被禁用,则会查找焦点组件的WHEN_ANCESTOR_OF_FOCUSED_COMPONENT输入映射,然后(如果没有找到绑定或者绑定到该键的操作被禁用)查找容器层次结构中每个组件的祖先的WHEN_ANCESTOR_OF_FOCUSED_COMPONENT输入映射。最终,将搜索根窗格的WHEN_ANCESTOR_OF_FOCUSED_COMPONENT输入映射。由于该输入映射对Enter键有有效绑定,因此会执行相应的操作,导致默认按钮被点击。

如何创建和移除键绑定

下面是一个示例,指定一个组件应该响应F2键:

component.getInputMap().put(KeyStroke.getKeyStroke("F2"),
                            "doSomething");
component.getActionMap().put("doSomething",
                             anAction);
//其中anAction是javax.swing.Action对象

如上述代码所示,要获取组件的动作映射,使用继承自JComponentgetActionMap方法。要获取输入映射,可以使用getInputMap(int)方法,其中整数是上述列表中的JComponent.WHEN_*FOCUSED*常量之一。或者,在常规情况下,常量为JComponent.WHEN_FOCUSED,可以直接使用没有参数的getInputMap方法。

要向其中一个映射添加条目,使用put方法。可以使用KeyStroke.getKeyStroke(String)方法来指定键,该方法返回一个KeyStroke对象。可以在此处找到创建Action(用于放入动作映射)的示例。

以下是一个稍微复杂一点的示例,指定一个组件应该像用户点击鼠标一样响应Space键。

component.getInputMap().put(KeyStroke.getKeyStroke("SPACE"),
                            "pressed");
component.getInputMap().put(KeyStroke.getKeyStroke("released SPACE"),
                            "released");
component.getActionMap().put("pressed",
                             pressedAction);
component.getActionMap().put("released",
                             releasedAction);
//其中pressedAction和releasedAction是javax.swing.Action对象

要使组件忽略通常会响应的按键,可以使用特殊的动作名称“none”。例如,以下代码使组件忽略 F2 键。

component.getInputMap().put(KeyStroke.getKeyStroke("F2"),
                            "none");

注意: 

上述代码并不会阻止相关的 WHEN_ANCESTOR_OF_FOCUSED_COMPONENTWHEN_IN_FOCUSED_WINDOW 输入映射被搜索 F2 键绑定。要阻止此搜索,必须使用有效的动作代替“none”。例如:

Action doNothing = new AbstractAction() {
    public void actionPerformed(ActionEvent e) {
        //什么都不做
    }
};
component.getInputMap().put(KeyStroke.getKeyStroke("F2"),
                            "doNothing");
component.getActionMap().put("doNothing",
                             doNothing);

键绑定 API

下表列出了常用的键绑定 API。还请参阅 API 表格 创建和使用操作,在章节 如何使用操作 中。

获取和使用 InputMaps
方法 目的
InputMap getInputMap()
InputMap getInputMap(int)
(在 JComponent 中)
获取组件的其中一个输入映射。参数可以是以下这些 JComponent 常量之一: WHEN_FOCUSEDWHEN_IN_FOCUSED_WINDOWWHEN_ANCESTOR_OF_FOCUSED_COMPONENT。无参数的方法获取 WHEN_FOCUSED 输入映射。
void put(KeyStroke, Object)
(在 InputMap 中)
设置与指定的按键绑定关联的动作名称。如果第二个参数是 null,则此方法将删除按键绑定。要使按键被忽略,可以使用 "none" 作为第二个参数。
static KeyStroke getKeyStroke(String)
(在 KeyStroke 中)
获取指定用户键盘活动的对象。常见的参数有 "alt shift X"、"INSERT" 和 "typed a"。有关完整详情和其他形式的 getKeyStroke 方法,请参阅 KeyStroke API 文档
获取和使用 ActionMaps
方法 目的
ActionMap getActionMap()
(在 JComponent 中)
获取将名称映射到组件的动作的对象。
void put(Object, Action)
(在 ActionMap 中)
设置与指定名称相关联的动作。如果第二个参数为 null,则此方法将删除该名称的绑定。

使用键绑定的示例

以下表格列出了使用键绑定的示例:

示例 描述位置 注释
TableFTFEditDemo 如何使用表格 在格式化文本字段上注册了一个键绑定,以在用户按下 Enter 键时验证输入。
TextComponentDemo 文本组件特性 在文本面板上注册了键绑定,以在用户按下 Control-B、Control-F、Control-P 和 Control-N 键时导航文本。

上一页: 如何使用焦点子系统
下一页: 如何在对话框中使用模态性