如何编写焦点侦听器

每当组件获得或失去键盘焦点时,就会触发焦点事件。无论是通过鼠标,键盘还是以编程方式发生焦点变化,都是如此。要熟悉基本焦点概念或获取有关焦点的详细信息,请参阅如何使用 Focus 子系统

本节说明如何通过在其上注册FocusListener实例来获取特定组件的焦点事件。要仅获得窗口焦点,请改为实现WindowFocusListener实例。要获得许多组件的焦点状态,请考虑在KeyboardFocusManager类上实现PropertyChangeListener实例,如如何使用 Focus 子系统中的跟踪焦点更改到多个组件中所述。

下面的示例演示焦点事件。该窗口显示各种组件。注册在每个组件上的焦点侦听器报告每个焦点获得和焦点丢失的事件。对于每个事件,都会报告焦点更改中涉及的其他组件对立组件。例如,当焦点从按钮移到文本字段时,按钮会触发焦点丢失事件(文本字段为相反的组件),然后文本字段会触发焦点获取事件(带有按钮作为相反的组件)。失去焦点以及获得焦点的事件可能是暂时的。例如,当窗口失去焦点时,会发生一个临时的焦点丢失事件。临时获得焦点的事件在弹出菜单上发生。

焦点事件窗口,该窗口演示键盘焦点更改时触发的事件。

运行示例

  • 单击启动按钮以使用Java™Web 开始(下载 JDK 7 或更高版本)运行 FocusEventDemo。另外,要自己编译和运行示例,请查阅example index

  • 您将在文本区域中看到“焦点已获得:JTextField”消息-其“相反组件”为空,因为它是第一个具有焦点的组件。

  • 单击标签。由于标签默认情况下无法获得焦点,因此没有任何反应。

  • 单击组合框。焦点丢失事件由文本字段触发,焦点获得事件由组合框触发。现在,组合框显示出它具有焦点,也许在文本周围带有虚线-确切地表示方式取决于外观。
    请注意,当焦点从一个组件更改为另一个组件时,第一个组件将触发焦点丢失事件,第二个组件将触发焦点获取事件。

  • 从组合框的菜单中选择一个选项。再次单击组合框。请注意,没有报告焦点事件。只要用户操作相同的组件,焦点就停留在该组件上。

  • 单击打印焦点事件的文本区域。什么也没发生,因为使用setRequestFocusEnabled(false)致使文本区域不可单击。

  • 单击文本字段以将焦点返回到初始组件。

  • 按键盘上的 Tab。焦点移到组合框,并跳过标签。

  • 再次按 Tab 键。焦点移至按钮。

  • 单击另一个窗口,以便 FocusEventDemo 窗口失去焦点。为该按钮生成一个临时的焦点丢失事件。

  • 单击 FocusEventDemo 窗口的顶部。该按钮触发了聚焦事件。

  • 按键盘上的 Tab。焦点移至列表。

  • 再次按 Tab 键。焦点移到文本区域。
    请注意,即使不允许您单击文本区域,也可以将其切换到该区域。这样,使用assistive technologies的用户就可以确定该组件及其包含的组件。该演示通过在文本区域上调用setRequestFocusEnabled(false)来禁用文本区域的单击焦点,同时保留其选项卡焦点功能。该演示程序可以使用setFocusable(false)true 从焦点循环中删除文本区域,但这将产生不幸的效果,使那些使用辅助技术的人无法使用该组件。

  • 再次按 Tab 键。焦点从列表移回到文本字段。您刚刚完成了聚焦周期。有关焦点术语和概念的讨论,请参见如何使用 Focus 子系统introduction

该演示的完整代码在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); //It's easier to see the focus change
                                  //if an item is selected.
        list.addFocusListener(this);
        JScrollPane listScrollPane = new JScrollPane(list);
        
        ...

        //Set up the area that reports focus-gained and focus-lost events.
        display = new JTextArea();
        display.setEditable(false);
        //The method setRequestFocusEnabled prevents a
        //component from being clickable, but it can still
        //get the focus through the keyboard - this ensures
        //user accessibility.
        display.setRequestFocusEnabled(false);
        display.addFocusListener(this);
        JScrollPane displayScrollPane = new JScrollPane(display);

        ...
    }
    ...
    public void focusGained(FocusEvent e) {
        displayMessage("Focus gained", e);
    }

    public void focusLost(FocusEvent e) {
        displayMessage("Focus lost", e);
    }

    void displayMessage(String prefix, FocusEvent e) {
        display.append(prefix
                       + (e.isTemporary() ? " (temporary):" : ":")
                       +  e.getComponent().getClass().getName()
                       + "; Opposite component: " 
                       + (e.getOppositeComponent() != null ?
                          e.getOppositeComponent().getClass().getName() : "null")
                       + newline); 
    }
    ...
}

Focus Listener API

FocusListener interface

对应的适配器类为FocusAdapter.

MethodPurpose
focusGained(FocusEvent)在被侦听的组件获得焦点之后调用。
focusLost(FocusEvent)在侦听组件失去焦点之后立即调用。

FocusEvent API

MethodPurpose
boolean isTemporary()如果失去焦点或获得焦点的事件是暂时的,则返回真实值。
Component getComponent()

(*在java.awt.event.ComponentEvent *中)
返回引发焦点事件的组件。
Component getOppositeComponent()返回焦点更改中涉及的其他组件。对于FOCUS_GAINED事件,这是失去焦点的组件。对于FOCUS_LOST事件,这是获得关注的组件。如果焦点更改涉及本机应用程序,位于不同 VM 或上下文中的 Java 应用程序或没有其他组件,则返回null

使用焦点侦听器的示例

下表列出了使用焦点侦听器的示例。

ExampleWhere DescribedNotes
FocusEventDemoThis section报告发生在多个组件上的所有焦点事件,以演示触发焦点事件的情况。
TrackFocusDemo如何使用 Focus 子系统自定义组件Picture实现了焦点侦听器,以在该组件为当前焦点所有者时在该组件周围绘制红色边框。