JavaSwing_8.1:焦点事件及其监听器 - FocusEvent、FocusListener

2021-02-22 14:58:36 浏览数 (1)

0 FocusEvent

低级别事件指示Component已获得或失去输入焦点。 由组件生成此低级别事件(如一个TextField)。 该事件被传递给每一个FocusListener或FocusAdapter注册,以接收使用组件的此类事件对象addFocusListener方法。 ( FocusAdapter对象实现FocusListener接口。)每个此类侦听器对象获取此FocusEvent当事件发生时。 有两个焦点事件级别:持久性和暂时性的。 永久焦点改变事件发生时焦点直接移动从一个组件到另一个,例如通过到requestFocus的(呼叫)或作为用户使用TAB键遍历组件。 当暂时丢失焦点的组件的另一个操作,比如释放Window或拖动滚动条的间接结果一时焦点变化的事件发生。 在这种情况下,原来的聚焦状态将被自动一旦操作完成恢复,或者,对于窗口失活的情况下,当窗口被重新激活。 永久和临时焦点事件使用FOCUS_GAINED和FOCUS_LOST事件id传递; 水平可以使用isTemporary()方法的事件区分开来。 如果未指定的行为将导致的id任何特定的参数FocusEvent实例不是从范围FOCUS_FIRST到FOCUS_LAST

1 FocusListener

用于在组件上接收键盘焦点事件的侦听器接口。 对处理焦点事件感兴趣的类

  • 要么实现此接口(以及它包含的所有方法)
  • 要么扩展抽象FocusAdapter类(仅覆盖感兴趣的方法)

然后,使用组件的addFocusListener方法向组件注册从该类创建的侦听器对象。 当组件获得或失去键盘焦点时,将调用侦听器对象中的相关方法,并将FocusEvent传递给它。

API

  • focusGained
  • focusLost

2 FocusAdapter

用于接收键盘焦点事件的抽象适配器类。 此类中的方法为空。 此类存在的目的是方便创建监听器对象。

继承此类来创建 FocusEvent 监听器,并针对感兴趣的事件重写方法。(如果你实现 FocusListener 接口,则必须定义该接口中的所有方法。此抽象类将所有这些方法都定义为 null,所以你只需针对所关心的事件重写方法即可)。

使用扩展的类创建一个侦听器对象,然后使用组件的 addFocusListener 方法向组件注册该监听器。当组件获得或失去键盘焦点时,可调用侦听器对象中的相关方法,并将 FocusEvent 传递给它。

API

  • focusGained
  • focusLost

3 如何编写焦点侦听器

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

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

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

代码语言:javascript复制
package events;
 
/*
 * FocusEventDemo.java
 *
 */
 
import java.util.Vector;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
 
public class FocusEventDemo extends JFrame
        implements FocusListener {
    final static String newline = "n";
    JTextArea display;
     
    public FocusEventDemo(String name) {
        super(name);
    }
     
    public void addComponentsToPane(final Container pane) {
        GridBagLayout gridbag = new GridBagLayout();
        pane.setLayout(gridbag);
         
        GridBagConstraints c = new GridBagConstraints();
         
        c.fill = GridBagConstraints.HORIZONTAL;
        c.weightx = 1.0;  //Make column as wide as possible.
        JTextField textField = new JTextField("A TextField");
        textField.setMargin(new Insets(0,2,0,2));
        textField.addFocusListener(this);
        gridbag.setConstraints(textField, c);
        add(textField);
         
        c.weightx = 0.1;  //Widen every other column a bit, when possible.
        c.fill = GridBagConstraints.NONE;
        JLabel label = new JLabel("A Label");
        label.setBorder(BorderFactory.createEmptyBorder(0,5,0,5));
        label.addFocusListener(this);
        gridbag.setConstraints(label, c);
        add(label);
         
        String comboPrefix = "ComboBox Item #";
        final int numItems = 15;
        Vector<String> vector = new Vector<String>(numItems);
        for (int i = 0; i < numItems; i  ) {
            vector.addElement(comboPrefix   i);
        }
        JComboBox comboBox = new JComboBox(vector);
        comboBox.addFocusListener(this);
        gridbag.setConstraints(comboBox, c);
        add(comboBox);
         
        c.gridwidth = GridBagConstraints.REMAINDER;
        JButton button = new JButton("A Button");
        button.addFocusListener(this);
        gridbag.setConstraints(button, c);
        add(button);
         
        c.weightx = 0.0;
        c.weighty = 0.1;
        c.fill = GridBagConstraints.BOTH;
        String listPrefix = "List Item #";
        Vector<String> listVector = new Vector<String>(numItems);
        for (int i = 0; i < numItems; i  ) {
            listVector.addElement(listPrefix   i);
        }
        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);
         
        gridbag.setConstraints(listScrollPane, c);
        add(listScrollPane);
         
        c.weighty = 1.0; //Make this row as tall as possible.
        c.gridheight = GridBagConstraints.REMAINDER;
        //Set up the area that reports focus-gained and focus-lost events.
        display = new JTextArea();
        display.setEditable(false);
        //The setRequestFocusEnabled method 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);
         
        gridbag.setConstraints(displayScrollPane, c);
        add(displayScrollPane);
        setPreferredSize(new Dimension(450, 450));
        ((JPanel)pane).setBorder(BorderFactory.createEmptyBorder(20,20,20,20));
    }
     
    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);
        display.setCaretPosition(display.getDocument().getLength());
    }
     
    /**
     * Create the GUI and show it.  For thread safety,
     * this method should be invoked from the
     * event dispatch thread.
     */
    private static void createAndShowGUI() {
        //Create and set up the window.
        FocusEventDemo frame = new FocusEventDemo("FocusEventDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
         
        //Set up the content pane.
        frame.addComponentsToPane(frame.getContentPane());
         
        //Display the window.
        frame.pack();
        frame.setVisible(true);
    }
     
    public static void main(String[] args) {
        /* Use an appropriate Look and Feel */
        try {
            //UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
            UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
        } catch (UnsupportedLookAndFeelException ex) {
            ex.printStackTrace();
        } catch (IllegalAccessException ex) {
            ex.printStackTrace();
        } catch (InstantiationException ex) {
            ex.printStackTrace();
        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
        }
         
        /* Turn off metal's use of bold fonts */
        UIManager.put("swing.boldMetal", Boolean.FALSE);
        //Schedule a job for the event dispatch thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}

单击启动按钮运行FocusEventDemo。 您将在文本区域中看到一条“焦点已获得:JTextField”消息-其“相反组件”为空,因为它是第一个具有焦点的组件。 单击标签。什么也没发生,因为默认情况下标签无法获得焦点。 单击组合框。焦点丢失事件由文本字段触发,焦点获得事件由组合框触发。现在,组合框显示它具有焦点,也许在文本周围有一条虚线-确切地表示方式取决于外观。 请注意,当焦点从一个组件更改为另一个组件时,第一个组件将触发焦点丢失事件,第二个组件将触发焦点获得事件。 从组合框的菜单中选择一个选项。再次单击组合框。请注意,没有报告焦点事件。只要用户操作相同的组件,焦点就会停留在该组件上。 单击打印焦点事件的文本区域。什么也没有发生,因为使用setRequestFocusEnabled(false)使文本区域不可点击。 单击文本字段以将焦点返回到初始组件。 按键盘上的Tab。焦点移到组合框,并跳过标签。 再次按Tab键。焦点移至按钮。 单击另一个窗口,以便FocusEventDemo窗口失去焦点。为按钮生成一个临时的焦点丢失事件。 单击FocusEventDemo窗口的顶部。该按钮触发了聚焦事件。 按键盘上的Tab。焦点移至列表。 再次按Tab键。焦点移到文本区域。 请注意,即使不允许您单击文本区域,也可以将其切换到该区域。这样一来,使用辅助技术的用户就可以确定组件在那里及其包含的内容。该演示通过在文本区域上调用setRequestFocusEnabled(false)来禁用文本区域的单击焦点,同时保留其选项卡焦点功能。该演示可以使用setFocusable(false)从焦点循环中真正删除该文本区域,但这将产生不幸的后果,使使用辅助技术的人员无法使用该组件。 再次按Tab键。焦点从列表移回到文本字段。您刚刚完成了一个聚焦周期。

0 人点赞