文档

Java™ 教程
隐藏目录
如何编写按键监听器
教程:使用Swing创建GUI
课程:编写事件监听器
章节:实现常用事件的监听器

如何编写键盘监听器

按键事件指示用户在键盘上输入。具体来说,当用户按下或释放键盘键时,焦点在组件上的时候,将触发按键事件。有关焦点的详细信息,请参阅如何使用焦点子系统


注意: 

要为特定按键定义特殊的反应,请使用按键绑定而不是按键监听器。有关更多信息,请参见如何使用按键绑定


关于按键事件,会发送两种基本类型的通知:

第一种类型的事件被称为键入事件。第二种类型是按键按下按键释放事件。

一般来说,您只对键入事件做出反应,除非您需要知道用户何时按下与字符不对应的按键。例如,要知道用户何时输入Unicode字符-无论是通过按下一个键(如'a')还是按下多个键的顺序-您需要处理键入事件。另一方面,要知道用户何时按下F1键,或者用户是否按下数字键盘上的'3'键,您需要处理按键按下事件。


注意: 

要触发键盘事件,组件必须具有键盘焦点。


要使组件获得键盘焦点,请按照以下步骤进行:

  1. 确保组件的isFocusable方法返回true。此状态允许组件接收焦点。例如,您可以通过在标签上调用setFocusable(true)方法来启用JLabel组件的键盘焦点。
  2. 确保在适当的时候组件请求焦点。对于自定义组件,实现一个鼠标监听器,当单击组件时调用requestFocusInWindow方法。

版本说明: 

焦点子系统会消耗焦点遍历键,如Tab和Shift Tab。如果您需要防止焦点遍历键被消耗,可以调用

component.setFocusTraversalKeysEnabled(false)

在触发按键事件的组件上。然后,您的程序必须自行处理焦点遍历。或者,您可以使用KeyEventDispatcher类预先侦听所有按键事件。焦点页面上有关焦点子系统的详细信息。


您可以获取有关特定按键按下事件的详细信息。例如,您可以查询按下事件以确定它是否来自操作键。操作键的示例包括复制、粘贴、上翻页、撤销以及箭头和功能键。您还可以查询按下或释放事件以确定触发事件的键的位置。大多数按键事件都来自标准键盘,但某些键(如Shift)的事件包含有关用户是在键盘的左侧还是右侧按下Shift键的信息。同样,数字'2'可以从标准键盘或数字键盘上键入。

对于键入事件,您可以获取键字符值以及使用的任何修饰符。


注意: 

除非它涉及到键入事件,否则不应该依赖于从getKeyChar返回的键字符值。


下面的示例演示了键盘事件。它包含一个文本字段,您可以在其中输入内容,然后是一个文本区域,每当文本字段触发键盘事件时,它会显示一条消息。窗口底部的按钮可以清除文本字段和文本区域的内容。

KeyEventDemo.html

试一下: 
  1. 点击“启动”按钮使用 Java™ Web Start 运行KeyEventDemo(下载 JDK 7 或更高版本)。或者,如果你想自己编译和运行示例,请参考示例索引启动 KeyEventDemo 应用程序
  2. 按下并释放键盘上的 A 键,输入小写字母 'a'。
    文本框会触发三个事件:按键事件、输入事件和释放事件。请注意,输入事件没有键码信息,按键和释放事件没有键字符信息。到目前为止,所有的事件都不是来自修改键或操作键,按键和释放事件上报的键位置很可能是标准的。
  3. 点击“清除”按钮。
    在下面的每个步骤之后,你可能需要这样做。
  4. 按下并释放 Shift 键。
    文本框会触发两个事件:按键和释放。因为 Shift 单独按下时不对应任何字符,所以文本框不会触发输入事件。
  5. 通过同时按下 Shift 和 A 键输入大写字母 'A'。
    你会看到以下事件,尽管可能不是按照这个顺序:按键(Shift)、按键(A)、输入('A')、释放(A)、释放(Shift)。请注意,Shift 在按键和按键事件中被列为修改键。
  6. 通过按下并释放大小写锁定键,然后按下 A 键输入大写字母 'A'。
    你会看到以下事件:按键(大小写锁定)、按键(A)、输入('A')、释放(A)。请注意,大小写锁定不被列为修改键。
  7. 按下 Tab 键。键盘事件监听器不会接收到 Tab 键按下或释放事件。这是因为焦点子系统会消耗焦点遍历键,比如 Tab 和 Shift Tab。按两次 Tab 键将焦点返回到文本区域。
  8. 按下一个功能键,比如 F3 键。你会发现功能键是一个操作键。
  9. 先按下左 Shift 键,然后按下右 Shift 键。按键和释放事件会指示哪个 Shift 键被按下。
  10. 按下数字键盘上的 Num Lock 键(如果你的键盘有数字键盘)。
    与大小写锁定一样,会触发按键事件,但没有释放事件。
  11. 在数字键盘上按下数字 2 键。你会看到数字 '2' 的按键、输入和释放事件。
  12. 在标准键盘上按下数字 2 键。同样,你会看到这三个事件消息。两个数字 2 键的输入事件是相同的。但是按键和释放事件指示了不同的键码和键位置。
  13. 再次按下 Num Lock 键。会触发一个释放事件。

你可以在KeyEventDemo.java中找到示例代码。这是演示的按键事件处理代码:

public class KeyEventDemo ...  implements KeyListener ... {
    ...//初始化发生的地方:
        typingArea = new JTextField(20);
        typingArea.addKeyListener(this);

        //如果你希望关闭焦点遍历,取消注释这行代码。
        //焦点子系统会消耗焦点遍历键,比如 Tab 和 Shift Tab。
        //如果取消注释下面的代码,这会禁用焦点遍历,Tab 事件将可用于按键事件监听器。
        //typingArea.setFocusTraversalKeysEnabled(false);
    ...
    /** 处理文本字段的按键输入事件。 */
    public void keyTyped(KeyEvent e) {
        displayInfo(e, "KEY TYPED: ");
    }

    /** 处理文本字段的按键按下事件。 */
    public void keyPressed(KeyEvent e) {
        displayInfo(e, "KEY PRESSED: ");
    }

    /** 处理文本字段的按键释放事件。 */
    public void keyReleased(KeyEvent e) {
        displayInfo(e, "KEY RELEASED: ");
    }
    ...
    private void displayInfo(KeyEvent e, String keyStatus){
        
        //如果事件是按键输入事件,你应该只依赖于按键字符。
        int id = e.getID();
        String keyString;
        if (id == KeyEvent.KEY_TYPED) {
            char c = e.getKeyChar();
            keyString = "按键字符 = '" + c + "'";
        } else {
            int keyCode = e.getKeyCode();
            keyString = "按键代码 = " + keyCode
                    + " ("
                    + KeyEvent.getKeyText(keyCode)
                    + ")";
        }
        
        int modifiersEx = e.getModifiersEx();
        String modString = "扩展修饰键 = " + modifiersEx;
        String tmpString = KeyEvent.getModifiersExText(modifiersEx);
        if (tmpString.length() > 0) {
            modString += " (" + tmpString + ")";
        } else {
            modString += " (无扩展修饰键)";
        }
        
        String actionString = "动作键? ";
        if (e.isActionKey()) {
            actionString += "是";
        } else {
            actionString += "否";
        }
        
        String locationString = "按键位置:";
        int location = e.getKeyLocation();
        if (location == KeyEvent.KEY_LOCATION_STANDARD) {
            locationString += "标准";
        } else if (location == KeyEvent.KEY_LOCATION_LEFT) {
            locationString += "左";
        } else if (location == KeyEvent.KEY_LOCATION_RIGHT) {
            locationString += "右";
        } else if (location == KeyEvent.KEY_LOCATION_NUMPAD) {
            locationString += "数字键盘";
        } else { // (location == KeyEvent.KEY_LOCATION_UNKNOWN)
            locationString += "未知";
        }
        
        ...//显示有关 KeyEvent 的信息...
    }
}

键盘监听器 API

KeyListener 接口

对应的适配器类是 KeyAdapter

方法 目的
keyTyped(KeyEvent) 在用户将一个 Unicode 字符键入被监听的组件后调用。
keyPressed(KeyEvent) 在用户按下键时,被监听的组件具有焦点时调用。
keyReleased(KeyEvent) 在用户释放键时,被监听的组件具有焦点时调用。

KeyEvent 类

KeyEvent 类从 InputEvent 类继承了许多有用的方法,例如 getModifiersEx,并从 ComponentEvent 类和 AWTEvent 类继承了几个有用的方法。请参阅鼠标监听器页面的 InputEvent 类表以获取完整列表。

方法 目的
int getKeyChar() 获取与此事件关联的Unicode字符。仅对键入事件可靠地使用此值。
int getKeyCode() 获取与此事件关联的键码。键码标识用户按下或释放的键盘上的特定键。KeyEvent类为常见的键定义了许多键码常量。例如,VK_A指定标有A的键,VK_ESCAPE指定Escape键。
String getKeyText(int)
String getKeyModifiersText(int)
返回事件的键码和修饰键的文本描述。
int getModifiersEx()
String getModifiersExText(int modifiers)
返回此事件的扩展修饰键掩码。这些方法是从InputEvent类继承的。扩展修饰键表示所有模态键的状态。getModifiersExText方法返回描述扩展修饰键和鼠标按钮的字符串。由于getModifiersEx和getModifiersExText方法提供了关于按键事件更多的信息,它们优先于getKeyText或getKeyModifiersText方法。
boolean isActionKey() 如果触发事件的键是操作键,则返回true。操作键的示例包括剪切、复制、粘贴、上页、大写锁定、箭头和功能键。此信息仅对按下和释放键的事件有效。
int getKeyLocation() 返回触发此事件的键的位置。这提供了一种区分键盘上出现多次的键(例如两个Shift键)的方法。可能的值为KEY_LOCATION_STANDARD、KEY_LOCATION_LEFT、KEY_LOCATION_RIGHT、KEY_LOCATION_NUMPAD或KEY_LOCATION_UNKNOWN。对于键入事件,此方法始终返回KEY_LOCATION_UNKNOWN。

使用键盘监听器的示例

以下表格列出了使用键盘监听器的示例。

示例 描述位置 注释
KeyEventDemo 本节 将在文本字段上发生的所有键盘事件报告,以展示键盘事件触发的情况。

上一页: 如何编写项目监听器
下一页: 如何编写列表数据监听器