文档

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

如何编写焦点监听器

焦点事件是在组件获得或失去键盘焦点时触发的。这是无论焦点的改变是通过鼠标、键盘还是编程方式进行的。要了解基本的焦点概念或获取关于焦点的详细信息,请参阅如何使用焦点子系统

本节将解释如何通过在特定组件上注册FocusListener实例来获取焦点事件。要仅获取窗口的焦点,请实现WindowFocusListener实例。要获取多个组件的焦点状态,请考虑在KeyboardFocusManager类上实现PropertyChangeListener实例,如跟踪多个组件的焦点变化中所述,在如何使用焦点子系统中。

以下示例演示了焦点事件。窗口显示了各种组件。在每个组件上注册的焦点侦听器报告每个获得焦点和失去焦点的事件。对于每个事件,焦点改变的另一个组件,即“对方组件”,也会报告出来。例如,当焦点从按钮切换到文本字段时,按钮会触发焦点失去事件(对方组件为文本字段),然后文本字段会触发焦点获得事件(对方组件为按钮)。焦点失去和焦点获得事件都可以是临时的。例如,当窗口失去焦点时,会发生临时的焦点失去事件。弹出菜单会发生临时的焦点获得事件。

演示焦点事件的焦点事件窗口

运行示例

  1. 点击“启动”按钮以使用Java™ Web Start运行FocusEventDemo(下载JDK 7或更高版本)。或者,如果要自己编译和运行示例,请参考示例索引启动FocusEventDemo应用程序
  2. 在文本区域中会显示“获得焦点: JTextField”消息——由于它是第一个获得焦点的组件,所以它的“相反组件”为空。
  3. 点击标签。由于默认情况下标签无法获得焦点,所以没有任何反应。
  4. 点击组合框。文本字段会触发一个焦点失去事件,组合框会触发一个焦点获得事件。组合框现在显示它拥有焦点,可能会有一个虚线框围绕文本——具体的表示方式取决于外观和感觉。
    注意,当焦点从一个组件转移到另一个组件时,第一个组件会在第二个组件触发焦点获得事件之前触发焦点失去事件。
  5. 从组合框的菜单中选择一个选项。再次点击组合框。注意没有焦点事件报告。只要用户操作的是同一个组件,焦点就会保持在该组件上。
  6. 点击打印焦点事件的文本区域。由于使用了setRequestFocusEnabled(false)使文本区域无法点击。
  7. 点击文本字段以将焦点返回到初始组件。
  8. 在键盘上按Tab键。焦点移动到组合框并跳过标签。
  9. 再次按Tab键。焦点移动到按钮。
  10. 点击其他窗口,使FocusEventDemo窗口失去焦点。按钮会生成一个临时的焦点失去事件。
  11. 点击FocusEventDemo窗口的顶部。按钮会触发一个焦点获得事件。
  12. 在键盘上按Tab键。焦点移动到列表。
  13. 再次按Tab键。焦点移动到文本区域。
    注意,即使您无法点击文本区域,您仍然可以通过Tab键将焦点移动到它。这样做是为了让使用辅助技术的用户可以确定组件的存在以及其内容。该演示通过在文本区域上调用setRequestFocusEnabled(false)来禁用了点击获得焦点的功能,但仍保留了通过Tab键获得焦点的能力。演示还可以使用setFocusable(false)来真正将文本区域从焦点循环中移除,但这将导致那些使用辅助技术的用户无法使用该组件。
  14. 再次按Tab键。焦点从列表返回到文本字段。您刚刚完成了一个焦点循环。请参阅How to Use the Focus Subsystem中的介绍,了解焦点术语和概念的讨论。

这个演示的完整代码在 FocusEventDemo.java 文件中。以下代码片段代表了焦点事件处理机制:

public class FocusEventDemo ... implements FocusListener ... {
    public FocusEventDemo() {
        ...
        JTextField textField = new JTextField("A TextField");
        textField.addFocusListener(this);
        ...
        JLabel label = new JLabel("A Label");
        label.addFocusListener(this);
        ...
        JComboBox comboBox = new JComboBox(vector);
        comboBox.addFocusListener(this);
        ...
        JButton button = new JButton("A Button");
        button.addFocusListener(this);
        ...
        JList list = new JList(listVector);
        list.setSelectedIndex(1); //如果选中一个项目,更容易看到焦点的变化
                                  //list.addFocusListener(this);
        JScrollPane listScrollPane = new JScrollPane(list);
        
        ...

        //设置报告焦点获得和焦点丢失事件的区域。
        display = new JTextArea();
        display.setEditable(false);
        //方法setRequestFocusEnabled可以防止
        //组件被点击,但仍然可以通过键盘获得焦点 - 这确保了
        //用户可访问性。
        display.setRequestFocusEnabled(false);
        display.addFocusListener(this);
        JScrollPane displayScrollPane = new JScrollPane(display);

        ...
    }
    ...
    public void focusGained(FocusEvent e) {
        displayMessage("获得焦点", e);
    }

    public void focusLost(FocusEvent e) {
        displayMessage("失去焦点", e);
    }

    void displayMessage(String prefix, FocusEvent e) {
        display.append(prefix
                       + (e.isTemporary() ? " (临时):" : ":")
                       +  e.getComponent().getClass().getName()
                       + "; 对应组件: " 
                       + (e.getOppositeComponent() != null ?
                          e.getOppositeComponent().getClass().getName() : "null")
                       + newline); 
    }
    ...
}

焦点监听器 API

焦点监听器接口

相应的适配器类是 FocusAdapter

方法 用途
focusGained(FocusEvent) 在监听的组件获得焦点后调用。
focusLost(FocusEvent) 在监听的组件失去焦点后调用。

FocusEvent API

方法 目的
boolean isTemporary() 如果焦点失去或获得事件是临时的,则返回true。
Component getComponent()
(java.awt.event.ComponentEvent)
返回触发焦点事件的组件。
Component getOppositeComponent() 返回与焦点更改相关的另一个组件。对于FOCUS_GAINED事件,这是失去焦点的组件。对于FOCUS_LOST事件,这是获得焦点的组件。如果焦点更改涉及本机应用程序、不同VM或上下文的Java应用程序,或者没有其他组件,则返回null

使用焦点监听器的示例

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

示例 描述位置 备注
FocusEventDemo 本节 报告在几个组件上发生的所有焦点事件,以演示焦点事件触发的情况。
TrackFocusDemo 使用焦点子系统 自定义组件Picture通过实现焦点监听器,在组件周围绘制红色边框。

上一页: 如何编写文档监听器
下一页: 如何编写内部框架监听器