如何使用键绑定

JComponent类支持键绑定,作为对用户键入的各个键做出响应的一种方式。以下是一些适当的键绑定示例:

  • 您正在创建一个自定义组件,并希望支持对其的键盘访问。
    例如,您可能希望组件在获得焦点并且用户按下 Space 键时做出反应。

  • 您要覆盖现有键绑定的行为。
    例如,如果您的应用程序通常以特定的方式对 F2 键的按下作出反应,则您可能希望它执行其他操作或忽略按键。

  • 您想为现有操作提供新的键绑定。
    例如,您可能强烈感到 Control-Shift-Insert 应该执行粘贴操作。

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

键绑定的替代方法是使用key listeners。按键侦听器是键盘 Importing 的低级interface,但是对于响应单个按键,按键绑定更为合适,并且往往会导致代码维护更加容易。如果要在组件没有焦点时激活键绑定,则键侦听器也很困难。按键绑定的一些优点是它们可以自我记录,考虑容纳层次结构,鼓励可重用的代码块(Action对象)以及允许轻松删除,自定义或共享操作。而且,它们使更改动作绑定的键变得容易。动作的另一个优点是它们具有启用状态,该状态提供了一种简便的方法来禁用该动作而不必跟踪其附加到哪个组件。

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

按键绑定的工作方式

JComponent提供的键绑定支持取决于InputMapActionMap类。ImportingMap 将击键绑定到动作名称,并且动作 Map 指定与每个动作名称相对应的action。从技术上讲,您无需在 Map 中使用动作名称;您可以将任何对象用作 Map 的“键”。但是,按照约定,您使用一个字符串 来命名一个动作。

每个InputMap/ActionMap都有一个通常来自用户interface的父级。每当外观改变时,都会重置父级。这样,开发人员指定的任何绑定都不会在外观更改时丢失。

每个JComponent都有一个动作图和三个 Importing 图。ImportingMap 对应于以下焦点情况:

  • JComponent.WHEN_FOCUSED

    • 该组件具有键盘焦点。 WHEN_FOCUSEDImportingMap 通常在组件没有子代时使用。例如,按钮使用WHEN_FOCUSEDMap 绑定 Space 键。
      这些绑定仅在组件具有焦点时才有效。
  • JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT

    • 该组件包含(或是)具有焦点的组件。此 ImportingMap 通常用于复合组件,即其实现取决于子组件的组件。例如,JTable使用WHEN_ANCESTOR_OF_FOCUSED_COMPONENT进行所有绑定,因此,如果用户正在编辑,则向上箭头键(例如)仍会更改所选单元格。
  • JComponent.WHEN_IN_FOCUSED_WINDOW

    • 组件的窗口要么具有焦点,要么包含具有焦点的组件。此 ImportingMap 通常用于助记符或加速器,无论焦点在窗口中的什么位置,它们都必须处于活动状态。

当用户键入一个键时,JComponent键事件处理代码将搜索一个或多个 ImportingMap,以找到该键的有效绑定。找到绑定后,它将在操作 Map 中查找相应的操作。如果启用了操作,则绑定有效并且执行该操作。如果已禁用,则 continue 搜索有效的绑定。

如果该键存在多个绑定,则仅使用找到的第一个有效绑定。ImportingMap 按以下 Sequences 检查:

  • 重点组件的WHEN_FOCUSEDImporting 图。

  • 重点组件的WHEN_ANCESTOR_OF_FOCUSED_COMPONENTImporting 图。

  • WHEN_ANCESTOR_OF_FOCUSED_COMPONENTImportingMap 的是焦点组件的父级,然后是其父级的父级,依此类推,从而 continue 包含层次结构。注意:将跳过禁用组件的 ImportingMap。

  • 搜索聚焦窗口中所有已启用组件的WHEN_IN_FOCUSED_WINDOWImportingMap。由于搜索组件的 Sequences 是不可预测的,因此请 避免重复WHEN_IN_FOCUSED_WINDOW绑定!

让我们考虑一下在两种典型的键绑定情况下发生的情况:一个按钮对 Space 键作出反应,一个带有默认按钮的框架对 Enter 键作出反应。

在第一种情况下,假定用户在JButton拥有键盘焦点的同时按下了 Space 键。首先,将事件通知给按钮的键侦听器。假设所有按键侦听器都不消耗该事件(通过在KeyEvent上调用consume方法),则查询按钮的WHEN_FOCUSEDImportingMap。找到绑定是因为JButton使用该 ImportingMap 将 Space 绑定到动作名称。在按钮的动作 Map 中查找动作名称,并调用该动作的actionPerformed方法。 KeyEvent已消耗,并且处理停止。

在第二种情况下,假定焦点位于具有默认按钮(使用JRootPane setDefaultButton方法设置)的框架内的任何位置时,按下 Enter 键。无论关注的组件是什么,都将首先通知其关键侦听器。假设它们都不消耗键事件,则将查询焦点组件的WHEN_FOCUSEDImportingMap。如果没有针对该键的绑定,或者禁用了与该键绑定的操作,那么将查询该焦点组件的WHEN_ANCESTOR_OF_FOCUSED_COMPONENTImportingMap,然后(如果未找到绑定或禁用与该键绑定的 Action),则针对每个组件的WHEN_ANCESTOR_OF_FOCUSED_COMPONENTImportingMap 包含层次结构中组件祖先的数量。final,搜索根窗格的WHEN_ANCESTOR_OF_FOCUSED_COMPONENTImportingMap。由于该 ImportingMap 具有 Enter 的有效绑定,因此将执行该操作,从而导致单击默认按钮。

如何制作和删除按键绑定

这是指定组件应对 F2 键做出反应的示例:

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

如前面的代码所示,要获取组件的操作图,请使用getActionMap方法(从JComponent继承)。要获取 ImportingMap,可以使用getInputMap(int)方法,其中整数是前面列表中所示的JComponent.WHEN_*FOCUSED*常量之一。或者,在通常情况下常量为JComponent.WHEN_FOCUSED的情况下,可以只使用不带参数的getInputMap

要将条目添加到其中一个 Map,请使用put方法。您可以使用KeyStroke对象指定键,您可以使用KeyStroke.getKeyStroke(String)方法获得该键。您可以在如何使用动作中找到创建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_COMPONENTWHEN_IN_FOCUSED_WINDOWImportingMap 中搜索 F2 键绑定。为防止此搜索,您必须使用有效的操作而不是“ none”。例如:

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

密钥绑定 API

下表列出了常用的键绑定 API。另请参阅如何使用动作部分中的 API 表创建和使用动作

获取和使用 InputMaps

MethodPurpose
InputMap getInputMap()

InputMap getInputMap(int)
(在JComponent中)
获取组件的 ImportingMap 之一。参数可以是以下JComponent常量之一:WHEN_FOCUSEDWHEN_IN_FOCUSED_WINDOWWHEN_ANCESTOR_OF_FOCUSED_COMPONENT。无参数方法获取WHEN_FOCUSEDImportingMap。
无效 put(KeyStroke,Object)
(在InputMap中)
设置与指定按键相关联的动作名称。如果第二个参数是null,则此方法将删除按键的绑定。要忽略按键,请使用"none"作为第二个参数。
静态 KeyStroke getKeyStroke(String)
(在KeyStroke中)
获取指定特定用户键盘活动的对象。典型的参数是“ alt shift X”,“ INSERT”和“ typed a”。有关详细信息和getKeyStroke方法的其他形式,请参见KeyStroke API 文档

获取和使用 ActionMap

MethodPurpose
ActionMap getActionMap()

(在JComponent中)
获取将名称 Map 为组件操作的对象。
无效 put(Object,Action)
(在ActionMap中)
设置与指定名称关联的操作。如果第二个参数是null,则此方法将删除名称的绑定。

使用键绑定的示例

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

ExampleWhere DescribedNotes
TableFTFEditDemo如何使用表格IntegerEditor类在格式文本字段上注册键绑定,以在用户按下 Enter 键时验证 Importing。
TextComponentDemoLiterals 组件功能当用户按下 Control-B,Control-F,Control-P 和 Control-N 键时,键绑定将注册在文本窗格上,以浏览文本。