# 如何使用键绑定

> 原文： [https://docs.oracle.com/javase/tutorial/uiswing/misc/keybinding.html](https://docs.oracle.com/javase/tutorial/uiswing/misc/keybinding.html)

`JComponent`类支持键绑定，作为响应用户键入的各个键的方式。以下是一些适当的键绑定示例：

*   您正在创建自定义组件，并希望支持键盘访问它。
    例如，您可能希望组件在具有焦点时做出反应，并且用户按下 Space 键。
*   您想要覆盖现有键绑定的行为。
    例如，如果您的应用程序通常以特定方式对按 F2 键做出反应，您可能希望它执行不同的操作或忽略按键操作。
*   您希望为现有操作提供新的键绑定。
    例如，您可能会强烈感觉到 Control-Shift-Insert 应该执行粘贴操作。

您通常不需要直接使用键绑定。它们通过助记符在幕后使用（由所有按钮和选项卡式窗格以及 [`JLabel`](https://docs.oracle.com/javase/8/docs/api/javax/swing/JLabel.html) 支持）和加速器（由菜单项支持）。您可以在[启用键盘操作](../components/menu.html#mnemonic)部分找到助记符和加速器的覆盖范围。

键绑定的替代方法是使用[键侦听器](../events/keylistener.html)。键侦听器可以作为键盘输入的低级接口，但是对于单个键的响应，键绑定更合适，并且更容易维护代码。如果在组件没有焦点时要激活键绑定，则键侦听器也很困难。密钥绑定的一些优点是它们有点自我记录，考虑包含层次结构，鼓励可重用的代码块（`Action`对象），并允许轻松删除，自定义或共享操作。此外，它们可以轻松更改操作绑定的键。 Actions 的另一个优点是它们具有一个启用状态，它提供了一种简单的方法来禁用该操作，而无需跟踪它所连接的组件。

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

*   [密钥绑定的工作原理](#maps)
*   [如何制作和删除键绑定](#howto)
*   [密钥绑定 API](#api)
*   [使用键绑定的示例](#eg)

`JComponent`提供的关键结合支持依赖于 [`InputMap`](https://docs.oracle.com/javase/8/docs/api/javax/swing/InputMap.html) 和 [`ActionMap`](https://docs.oracle.com/javase/8/docs/api/javax/swing/ActionMap.html) 类。输入映射将关键笔划绑定到动作名称，动作映射指定与每个动作名称对应的[动作](action.html)。从技术上讲，您不需要在地图中使用动作名称;你可以使用任何对象作为地图的“关键”。但是，按照惯例，您使用命名操作的字符串。

每个`InputMap` / `ActionMap`都有一个通常来自 UI 的父级。无论何时更改外观，都会重置父级。这样，开发人员指定的任何绑定都不会因外观更改而丢失。

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

`JComponent.WHEN_FOCUSED`

The component has the keyboard focus. The `WHEN_FOCUSED` input map is typically used when the component has no children. For example, buttons bind the Space key using the `WHEN_FOCUSED` map.
These bindings are only effective when the component has focus.

`JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT`

The component contains (or is) the component that has the focus. This input map is commonly used for a composite component — a component whose implementation depends on child components. For example, `JTable`s make all their bindings using `WHEN_ANCESTOR_OF_FOCUSED_COMPONENT` so that if the user is editing, the up-arrow key (for example) still changes the selected cell.

`JComponent.WHEN_IN_FOCUSED_WINDOW`

The component's window either has the focus or contains the component that has the focus. This input map is commonly used for mnemonics or accelerators, which need to be active regardless of where focus is in the 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`](https://docs.oracle.com/javase/8/docs/api/java/awt/event/InputEvent.html#consume--) 方法），则查看按钮的`WHEN_FOCUSED`输入映射。找到绑定是因为`JButton`使用该输入映射将 Space 绑定到操作名称。在按钮的动作映射中查找动作名称，并调用动作的`actionPerformed`方法。 `KeyEvent`被消耗，处理停止。

在第二种情况下，假设在焦点位于具有默认按钮的帧内的任何位置时按下 Enter 键（使用`JRootPane` [`setDefaultButton`](https://docs.oracle.com/javase/8/docs/api/javax/swing/JRootPane.html#setDefaultButton-javax.swing.JButton-) 方法设置）。无论焦点组件是什么，其关键听众都会首先得到通知。假设它们都没有消耗关键事件，则咨询聚焦组件的`WHEN_FOCUSED`输入映射。如果它没有绑定键或禁用绑定到键的 Action，则查询焦点组件的`WHEN_ANCESTOR_OF_FOCUSED_COMPONENT`输入映射，然后（如果未找到绑定或禁用绑定到该键的 Action）`WHEN_ANCESTOR_OF_FOCUSED_COMPONENT`包含层次结构中每个组件的祖先的输入映射。最终，搜索根窗格的`WHEN_ANCESTOR_OF_FOCUSED_COMPONENT`输入映射。由于该输入映射具有 Enter 的有效绑定，因此将执行该操作，从而导致单击默认按钮。

以下是指定组件应对 F2 键做出反应的示例：

```
component.getInputMap().put(KeyStroke.getKeyStroke("F2"),
                            "doSomething");
component.getActionMap().put("doSomething",
                             anAction);
//where anAction is a javax.swing.Action

```

如前面的代码所示，要获取组件的动作映射，请使用`getActionMap`方法（继承自`JComponent`）。要获取输入映射，可以使用`getInputMap(int)`方法，其中整数是前面列表中显示的`JComponent.WHEN_*FOCUSED*`常量之一。或者，在常量为`JComponent.WHEN_FOCUSED`的通常情况下，您可以只使用没有参数的`getInputMap`。

要向其中一个地图添加条目，请使用`put`方法。使用`KeyStroke`对象指定键，可以使用 [`KeyStroke.getKeyStroke(String)`](https://docs.oracle.com/javase/8/docs/api/javax/swing/KeyStroke.html#getKeyStroke-java.lang.String-) 方法获得。您可以在[如何使用动作](../misc/action.html)中找到创建`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);
//where pressedAction and releasedAction are javax.swing.Action objects

```

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

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

```

* * *

**Note:** 

上述代码不会阻止搜索相关的`WHEN_ANCESTOR_OF_FOCUSED_COMPONENT`和`WHEN_IN_FOCUSED_WINDOW`输入映射以进行 F2 键绑定。要阻止此搜索，您必须使用有效操作而不是“无”。例如：

```
Action doNothing = new AbstractAction() {
    public void actionPerformed(ActionEvent e) {
        //do nothing
    }
};
component.getInputMap().put(KeyStroke.getKeyStroke("F2"),
                            "doNothing");
component.getActionMap().put("doNothing",
                             doNothing);

```

* * *

下表列出了常用的键绑定 API。另请参见[如何使用动作](action.html)一节中的 API 表[创建和使用动作](action.html#actionapi)。

*   [创建和使用 InputMaps](#inputmap)
*   [创建和使用 ActionMaps](#actionmap)


| 方法 | 目的 |
| :-- | :-- |
| [InputMap getInputMap（）](https://docs.oracle.com/javase/8/docs/api/javax/swing/JComponent.html#getInputMap--)
[InputMap getInputMap（int）](https://docs.oracle.com/javase/8/docs/api/javax/swing/JComponent.html#getInputMap-int-)
_（在`JComponent`中）_ | 获取组件的输入映射之一。参数可以是这些`JComponent`常数之一：`WHEN_FOCUSED`，`WHEN_IN_FOCUSED_WINDOW`或`WHEN_ANCESTOR_OF_FOCUSED_COMPONENT`。无参数方法获取`WHEN_FOCUSED`输入映射。 |
| [void put（KeyStroke，Object）](https://docs.oracle.com/javase/8/docs/api/javax/swing/InputMap.html#put-javax.swing.KeyStroke-java.lang.Object-)
_（在`InputMap`中）_ | 设置与指定键击关联的操作名称。如果第二个参数是`null`，则此方法将删除键击的绑定。要忽略键击，请使用`"none"`作为第二个参数。 |
| [static KeyStroke getKeyStroke（String）](https://docs.oracle.com/javase/8/docs/api/javax/swing/KeyStroke.html#getKeyStroke-java.lang.String-)
_（在`KeyStroke`中）_ | 获取指定特定用户键盘活动的对象。典型的参数是“alt shift X”，“INSERT”和“typed a”。有关`getKeyStroke`方法的详细信息和其他形式，请参见 [`KeyStroke` API 文档](https://docs.oracle.com/javase/8/docs/api/javax/swing/KeyStroke.html)。 |


| 方法 | 目的 |
| :-- | :-- |
| [ActionMap getActionMap（）](https://docs.oracle.com/javase/8/docs/api/javax/swing/JComponent.html#getActionMap--)
_（在`JComponent`中）_ | 获取将名称映射到组件的操作的对象。 |
| [void put（对象，动作）](https://docs.oracle.com/javase/8/docs/api/javax/swing/ActionMap.html#put-java.lang.Object-javax.swing.Action-)
_（在`ActionMap`中）_ | 设置与指定名称关联的操作。如果第二个参数是`null`，则此方法将删除名称的绑定。 |

下表列出了使用键绑定的示例：

| 例 | 在哪里描述 | 笔记 |
| :-- | :-- | :-- |
| [TableFTFEditDemo](../examples/components/index.html#TableFTFEditDemo) | [如何使用表格](../components/table.html) | [IntegerEditor](../components/../examples/components/TableFTFEditDemoProject/src/components/IntegerEditor.java) 类在格式化文本字段上注册键绑定，以在用户按下 Enter 键时验证输入。 |
| [TextComponentDemo](../examples/components/index.html#TextComponentDemo) | [文本组件功能](../components/generaltext.html) | 当用户按下 Control-B，Control-F，Control-P 和 Control-N 键时，键绑定被注册在文本窗格上以浏览文本。 |