Java 中文官方教程 2022 版(二十五)

原文:docs.oracle.com/javase/tutorial/reallybigindex.html

如何编写容器侦听器

原文:docs.oracle.com/javase/tutorial/uiswing/events/containerlistener.html

容器事件是由Container在组件被添加到容器或从容器中移除后触发的。这些事件仅用于通知 ------ 组件成功添加或移除时不需要容器侦听器。

以下示例演示了容器事件。通过点击添加按钮移除按钮,您可以向窗口底部的面板添加按钮或从中移除按钮。每次向面板添加或移除按钮时,面板都会触发一个容器事件,并通知面板的容器侦听器。侦听器在窗口顶部的文本区域中显示描述性消息。


试一试:

  1. 点击启动按钮以使用Java™ Web Start运行 ContainerEventDemo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。

  2. 点击标有添加按钮的按钮。

    您将看到一个按钮出现在窗口底部附近。容器侦听器对产生的组件添加事件做出反应,通过在窗口顶部显示"JButton #1 was added to javax.swing.JPanel"。

  3. 点击标有移除按钮的按钮。

    这将从面板中最近添加的按钮中移除一个,导致容器侦听器接收到组件移除事件。


您可以在ContainerEventDemo.java中找到演示的代码。以下是演示的容器事件处理代码:

java 复制代码
public class ContainerEventDemo ... implements ContainerListener ... {
    *...//where initialization occurs:*
        buttonPanel = new JPanel(new GridLayout(1,1));
        buttonPanel.addContainerListener(this);
    ...
    public void componentAdded(ContainerEvent e) {
        displayMessage(" added to ", e);
    }

    public void componentRemoved(ContainerEvent e) {
        displayMessage(" removed from ", e);
    }

    void displayMessage(String action, ContainerEvent e) {
        display.append(((JButton)e.getChild()).getText()
                       + " was"
                       + action
                       + e.getContainer().getClass().getName()
                       + newline);
    }
    ...
}

容器侦听器 API

容器侦听器接口

相应的适配器类是ContainerAdapter

方法 目的
componentAdded(ContainerEvent) 在被监听容器中的组件被添加后调用。
componentRemoved(ContainerEvent) 在被监听容器中的组件被移除后调用。

ContainerEvent 类

方法 目的
获取子组件 getChild() 返回触发此事件的组件的添加或移除。
获取容器 getContainer() 返回触发此事件的容器。您可以使用这个方法代替getSource方法。

使用容器监听器的示例

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

示例 描述位置 备注
ContainerEventDemo 本节 报告发生在单个面板上的所有容器事件,以展示触发容器事件的情况。

如何编写文档监听器

原文:docs.oracle.com/javase/tutorial/uiswing/events/documentlistener.html

Swing 文本组件使用Document来表示其内容。文档事件发生在文档的内容以任何方式更改时。你将文档监听器附加到文本组件的文档上,而不是文本组件本身。有关更多信息,请参见实现文档过滤器。

以下示例演示了两个纯文本组件上的文档事件。


试一试:

  1. 点击"启动"按钮以使用Java™ Web Start运行 DocumentEventDemo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。

  2. 在窗口左上角的文本字段或文本字段下方的文本区域中键入文本。

    每次键入字符时都会触发一个文档事件。

  3. 使用退格键删除文本。

    每次按退格键键入时都会触发一个文档事件。

  4. 选择文本,然后通过按退格键或使用CTRL-X(剪切)等键盘命令删除。

    整个删除操作会触发一个文档事件。

  5. 使用键盘命令如CTRL-C(复制)和CTRL-V(粘贴)将文本从一个文本组件复制到另一个文本组件。

    无论粘贴的文本长度如何,整个粘贴操作都会触发一个文档事件。如果在发出粘贴命令之前在目标文本组件中选择文本,则会触发额外的文档事件,因为首先删除所选文本。


你可以在DocumentEventDemo.java中找到演示代码。以下是演示文档事件处理代码:

java 复制代码
public class DocumentEventDemo ... {
    *...//where initialization occurs:*
    textField = new JTextField(20);
    textField.addActionListener(new MyTextActionListener());
    textField.getDocument().addDocumentListener(new MyDocumentListener());
    textField.getDocument().putProperty("name", "Text Field");

    textArea = new JTextArea();
    textArea.getDocument().addDocumentListener(new MyDocumentListener());
    textArea.getDocument().putProperty("name", "Text Area");
    ...

class MyDocumentListener implements DocumentListener {
    String newline = "\n";

    public void insertUpdate(DocumentEvent e) {
        updateLog(e, "inserted into");
    }
    public void removeUpdate(DocumentEvent e) {
        updateLog(e, "removed from");
    }
    public void changedUpdate(DocumentEvent e) {
        //Plain text components do not fire these events
    }

    public void updateLog(DocumentEvent e, String action) {
        Document doc = (Document)e.getDocument();
        int changeLength = e.getLength();
        displayArea.append(
            changeLength + " character" +
            ((changeLength == 1) ? " " : "s ") +
            action + doc.getProperty("name") + "." + newline +
            "  Text length = " + doc.getLength() + newline);
    }
}

文档监听器不应修改文档的内容;在监听器被通知更改时,更改已经完成。相反,编写一个自定义文档,覆盖insertStringremove方法,或两者都覆盖。详细信息请参见监听文档更改。

文档监听器 API

文档监听器接口

DocumentListener没有适配器类。

方法 目的
changedUpdate(DocumentEvent) 当监听文档中的一些文本样式发生变化时调用。这种事件仅从StyledDocument中触发 --- PlainDocument不会触发这些事件。
insertUpdate(DocumentEvent) 当文本插入到监听文档中时调用。
removeUpdate(DocumentEvent) 当从监听文档中删除文本时调用。

文档事件接口

每个文档事件方法都会传递一个实现DocumentEvent接口的对象。通常,这是AbstractDocument中定义的DefaultDocumentEvent的实例。

方法 目的
获取文档的 Document 对象 返回触发事件的文档。请注意,DocumentEvent接口不继承自EventObject。因此,它不继承getSource方法。
获取长度的 int 方法 返回更改的长度。
获取偏移量的 int 方法 返回更改的第一个字符在文档中的位置。
获取更改的 ElementChange 方法 返回文档中已更改的元素及其详细信息。ElementChange是在DocumentEvent接口中定义的一个接口。
获取类型的 EventType 方法 返回发生的更改类型。EventType是在DocumentEvent接口中定义的一个类,列举了文档上可能发生的更改类型:插入文本、删除文本和更改文本样式。

使用文档监听器的示例

以下表列出了使用文档监听器的示例。

示例 描述位置 注意事项
DocumentEventDemo 本节 报告文本字段和文本区域上发生的所有文档事件。一个监听器同时监听两个文本组件,并使用文档上的客户端属性来确定哪个组件触发了事件。
TextComponentDemo 监听文档变化 每当被监听文档中的文本发生变化时更新变更日志。本示例中的文档支持样式文本,因此在本示例中调用changedUpdate。需要额外的源文件:DocumentSizeFilter

如何编写焦点监听器

原文:docs.oracle.com/javase/tutorial/uiswing/events/focuslistener.html

焦点事件在组件获得或失去键盘焦点时触发。无论焦点变化是通过鼠标、键盘还是程序化操作,都是如此。要熟悉基本的焦点概念或获取关于焦点的详细信息,请参阅如何使用焦点子系统。

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

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

运行示例

  1. 点击"启动"按钮以使用Java™ Web Start运行 FocusEventDemo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。

  2. 在文本区域中会看到"焦点获得:JTextField"的消息 --- 其"对立组件"为 null,因为它是第一个获得焦点的组件。

  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 键。焦点从列表返回到文本字段。你刚刚完成了一个焦点循环。请参阅介绍中的如何使用焦点子系统来讨论焦点术语和概念。

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

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); 
    }
    ...
}

焦点监听器 API

焦点监听器接口

对应的适配器类是FocusAdapter

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

焦点事件 API

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

使用焦点监听器的示例

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

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

如何编写内部框架监听器

原文:docs.oracle.com/javase/tutorial/uiswing/events/internalframelistener.html

InternalFrameListener类似于WindowListener。与窗口监听器类似,内部框架监听器监听发生在"窗口"首次显示、销毁、图标化、取消图标化、激活或停用时的事件。在使用内部框架监听器之前,请熟悉如何编写窗口监听器中的WindowListener接口。

下图中显示的应用程序演示了内部框架事件。该应用程序监听来自事件生成器框架的内部框架事件,显示描述每个事件的消息。


试试这个:

  1. 点击"启动"按钮以使用Java™ Web Start运行 InternalFrameEventDemo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。

  2. 点击显示内部框架按钮,打开事件生成器内部框架。

    在显示区域中应该看到一个"内部框架已打开"的消息。

  3. 尝试各种操作,看看会发生什么。例如,点击事件生成器以激活它。点击事件监视器以使事件生成器停用。点击事件生成器的装饰以将窗口图标化、最大化、最小化和关闭。

    查看如何编写窗口监听器以获取有关您将看到的事件类型的信息。


这是处理内部框架事件的代码:

java 复制代码
public class InternalFrameEventDemo ...
                     implements InternalFrameListener ... {
    ...

    public void internalFrameClosing(InternalFrameEvent e) {
        displayMessage("Internal frame closing", e);
    }

    public void internalFrameClosed(InternalFrameEvent e) {
        displayMessage("Internal frame closed", e);
        listenedToWindow = null;
    }

    public void internalFrameOpened(InternalFrameEvent e) {
        displayMessage("Internal frame opened", e);
    }

    public void internalFrameIconified(InternalFrameEvent e) {
        displayMessage("Internal frame iconified", e);
    }

    public void internalFrameDeiconified(InternalFrameEvent e) {
        displayMessage("Internal frame deiconified", e);
    }

    public void internalFrameActivated(InternalFrameEvent e) {
        displayMessage("Internal frame activated", e);
    }

    public void internalFrameDeactivated(InternalFrameEvent e) {
        displayMessage("Internal frame deactivated", e);
    }

    void displayMessage(String prefix, InternalFrameEvent e) {
        String s = prefix + ": " + e.getSource(); 
        display.append(s + newline);
    }

    public void actionPerformed(ActionEvent e) {
        if (SHOW.equals(e.getActionCommand())) {
            ...
            if (listenedToWindow == null) {
                listenedToWindow = new JInternalFrame("Event Generator",
                                                      true,  //resizable
                                                      true,  //closable
                                                      true,  //maximizable
                                                      true); //iconifiable
                //We want to reuse the internal frame, so we need to
                //make it hide (instead of being disposed of, which is
                //the default) when the user closes it.
                listenedToWindow.setDefaultCloseOperation(
                                        WindowConstants.HIDE_ON_CLOSE);

                listenedToWindow.addInternalFrameListener(this);
                ...
            }
        } 
        ...
    }
}

内部框架监听器 API

内部框架监听器接口

相应的适配器类是InternalFrameAdapter

方法 目的
internalFrameOpened(InternalFrameEvent) 在监听的内部框架首次显示后调用。
internalFrameClosing(InternalFrameEvent) 响应用户请求关闭监听的内部框架时调用。默认情况下,JInternalFrame在用户关闭时隐藏窗口。您可以使用JInternalFramesetDefaultCloseOperation方法指定另一个选项,该选项必须是DISPOSE_ON_CLOSEDO_NOTHING_ON_CLOSE(都在WindowConstants中定义,JInternalFrame实现了该接口)。或者通过在内部框架的监听器中实现internalFrameClosing方法,您可以添加自定义行为(例如弹出对话框或保存数据)以响应内部框架的关闭。
internalFrameClosed(InternalFrameEvent) 在监听的内部框架被销毁后立即调用。
internalFrameIconified(InternalFrameEvent) internalFrameDeiconified(InternalFrameEvent) 在监听的内部框架被图标化或取消图标化后立即调用。
internalFrameActivated(InternalFrameEvent) internalFrameDeactivated(InternalFrameEvent) 在监听的内部框架被激活或停用后立即调用。

每个内部框架事件方法都有一个参数:一个InternalFrameEvent对象。InternalFrameEvent类定义了没有通用用途的方法。要获取触发事件的内部框架,使用getSource方法,该方法是InternalFrameEventjava.util.EventObject继承而来。

使用内部框架监听器的示例

目前没有其他源文件包含内部框架监听器。但是,内部框架监听器与WindowListener非常相似,几个 Swing 程序都有窗口监听器:

示例 描述位置 注释
InternalFrameEventDemo 本节 报告发生在一个内部框架上的所有内部框架事件,以演示触发内部框架事件的情况。
DialogDemo 文本组件功能 CustomDialog.java 使用 setDefaultCloseOperation 而不是窗口监听器来确定用户关闭窗口时要采取的操作。
SliderDemo 如何使用滑块 监听窗口最小化和最大化事件,以便在窗口不可见时停止动画。

如何编写项目监听器

原文:docs.oracle.com/javase/tutorial/uiswing/events/itemlistener.html

项目事件由实现ItemSelectable接口的组件触发。通常,ItemSelectable组件维护一个或多个项目的开/关状态。触发项目事件的 Swing 组件包括按钮,如复选框、复选菜单项、切换按钮等...以及组合框。

这里是从ComponentEventDemo.java中提取的一些项目事件处理代码:

java 复制代码
*//where initialization occurs*
checkbox.addItemListener(this);
...
public void itemStateChanged(ItemEvent e) {
    if (e.getStateChange() == ItemEvent.SELECTED) {
        label.setVisible(true);
        ...
    } else {
        label.setVisible(false);
    }
}

项目监听器 API

项目监听器接口

因为ItemListener只有一个方法,所以没有相应的适配器类。

方法 目的
itemStateChanged(ItemEvent) 在被监听组件状态改变后调用。

项目事件类

方法 目的
Object getItem() 返回与状态改变的项目相关联的组件特定对象。通常这是一个包含所选项目文本的String
ItemSelectable getItemSelectable() 返回触发项目事件的组件。您可以使用这个方法代替getSource方法。
int getStateChange() 返回项目的新状态。ItemEvent类定义了两种状态:SELECTEDDESELECTED

使用项目监听器的示例

下表列出了一些使用项目监听器的示例。

示例 描述位置 注释
ComponentEventDemo 本节和如何编写组件监听器 监听复选框上的项目事件,确定标签是否可见。
CheckBoxDemo 如何使用复选框 四个复选框共享一个项目监听器,该监听器使用getItemSelected来确定哪个复选框触发了事件。
MenuDemo 如何使用菜单 监听复选框菜单项上的项目事件。
MenuDemo 如何使用滚动窗格 监听切换按钮上的项目事件。

如何编写键盘监听器

原文:docs.oracle.com/javase/tutorial/uiswing/events/keylistener.html

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


注意:

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


有关两种基本按键事件的通知已发送:

  • 输入 Unicode 字符

  • 在键盘上按下或释放按键

第一种事件称为按键输入 事件。第二种是按键按下按键释放事件。

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


注意:

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


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

  1. 确保组件的isFocusable方法返回true。这种状态允许组件接收焦点。例如,您可以通过在标签上调用setFocusable(true)方法为JLabel组件启用键盘焦点。

  2. 确保组件在适当时请求焦点。对于自定义组件,实现一个鼠标监听器,在组件被点击时调用requestFocusInWindow方法。


版本说明:

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

java 复制代码
component.setFocusTraversalKeysEnabled(false)

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


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

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


注意:

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


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


尝试一下:

  1. 点击"启动"按钮以使用Java™ Web Start运行 KeyEventDemo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。

  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. 如果你的键盘有数字键盘,按下数字锁定键。

    至于大写锁定键,有一个按下事件,但没有释放事件。

  11. 在数字键盘上按下 '2' 键。你会看到数字 '2' 的按下、键输入和释放事件。

  12. 在标准键盘上按下 '2' 键。同样,你会看到三个事件消息。两个数字 2 键的键输入事件是相同的。但按下和释放事件会显示不同的键代码和不同的键位置。

  13. 再次按下数字锁定键。会触发一个释放事件。


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

java 复制代码
public class KeyEventDemo ...  implements KeyListener ... {
    *...//where initialization occurs:*
        typingArea = new JTextField(20);
        typingArea.addKeyListener(this);

        //Uncomment this if you wish to turn off focus
        //traversal.  The focus subsystem consumes
        //focus traversal keys, such as Tab and Shift Tab.
        //If you uncomment the following line of code, this
        //disables focus traversal and the Tab events 
        //become available to the key event listener.
        //typingArea.setFocusTraversalKeysEnabled(false);
    ...
    /** Handle the key typed event from the text field. */
    public void keyTyped(KeyEvent e) {
        displayInfo(e, "KEY TYPED: ");
    }

    /** Handle the key-pressed event from the text field. */
    public void keyPressed(KeyEvent e) {
        displayInfo(e, "KEY PRESSED: ");
    }

    /** Handle the key-released event from the text field. */
    public void keyReleased(KeyEvent e) {
        displayInfo(e, "KEY RELEASED: ");
    }
    ...
    private void displayInfo(KeyEvent e, String keyStatus){

        //You should only rely on the key char if the event
        //is a key typed event.
        int id = e.getID();
        String keyString;
        if (id == KeyEvent.KEY_TYPED) {
            char c = e.getKeyChar();
            keyString = "key character = '" + c + "'";
        } else {
            int keyCode = e.getKeyCode();
            keyString = "key code = " + keyCode
                    + " ("
                    + KeyEvent.getKeyText(keyCode)
                    + ")";
        }

        int modifiersEx = e.getModifiersEx();
        String modString = "extended modifiers = " + modifiersEx;
        String tmpString = KeyEvent.getModifiersExText(modifiersEx);
        if (tmpString.length() > 0) {
            modString += " (" + tmpString + ")";
        } else {
            modString += " (no extended modifiers)";
        }

        String actionString = "action key? ";
        if (e.isActionKey()) {
            actionString += "YES";
        } else {
            actionString += "NO";
        }

        String locationString = "key location: ";
        int location = e.getKeyLocation();
        if (location == KeyEvent.KEY_LOCATION_STANDARD) {
            locationString += "standard";
        } else if (location == KeyEvent.KEY_LOCATION_LEFT) {
            locationString += "left";
        } else if (location == KeyEvent.KEY_LOCATION_RIGHT) {
            locationString += "right";
        } else if (location == KeyEvent.KEY_LOCATION_NUMPAD) {
            locationString += "numpad";
        } else { // (location == KeyEvent.KEY_LOCATION_UNKNOWN)
            locationString += "unknown";
        }

        *...//Display information about the KeyEvent...*
    }
}

键盘监听器 API

键盘监听器接口

对应的适配器类是KeyAdapter

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

KeyEvent 类

KeyEvent 类从InputEvent 类继承了许多有用的方法,比如 getModifiersEx,以及从ComponentEventAWTEvent 类继承了一些有用的方法。在鼠标监听器页面的 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方法返回描述扩展修饰符键和鼠标按钮的字符串。由于getModifiersExgetModifiersExText方法提供了更多关于按键事件的信息,因此它们比getKeyTextgetKeyModifiersText方法更受青睐。
boolean isActionKey() 如果触发事件的键是动作键,则返回 true。动作键的示例包括剪切、复制、粘贴、翻页、大写锁定、箭头和功能键。此信息仅适用于按键按下和按键释放事件。
int getKeyLocation() 返回触发此事件的键的位置。这提供了一种区分键盘上出现多次的键的方法,例如两个 Shift 键。可能的值为KEY_LOCATION_STANDARDKEY_LOCATION_LEFTKEY_LOCATION_RIGHTKEY_LOCATION_NUMPADKEY_LOCATION_UNKNOWN。对于按键输入事件,此方法始终返回KEY_LOCATION_UNKNOWN

使用键盘监听器的示例

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

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

如何编写列表数据监听器

原文:docs.oracle.com/javase/tutorial/uiswing/events/listdatalistener.html

当可变列表的内容发生变化时,会触发列表数据事件。由于模型而不是组件触发这些事件,因此您必须向列表模型注册列表数据监听器。如果您没有显式创建具有可变列表模型的列表,则您的列表是不可变的,其模型不会触发这些事件。


注意:

组合框 模型也会触发列表数据事件。但是,除非你正在创建自定义组合框模型,否则通常不需要了解它们。


以下示例演示了可变列表上的列表数据事件:


试试这个:

  1. 点击启动按钮以使用Java™ Web Start运行 ListDataEventDemo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。

  2. 输入你最喜欢的滑雪胜地的名称,然后点击添加 按钮。将触发一个 intervalAdded 事件。

  3. 在列表中选择几个连续的项目,然后点击删除 按钮。将触发一个 intervalRemoved 事件。

  4. 选择一个项目,然后使用箭头按钮将其上移或下移。将触发两个 contentsChanged 事件 --- 一个是移动的项目,另一个是被替换的项目。


你可以在ListDataEventDemo.java中找到演示的代码。以下是在列表模型上注册列表数据监听器并实现监听器的代码:

java 复制代码
//*...where member variables are declared...*
private DefaultListModel listModel;
...
//Create and populate the list model
listModel = new DefaultListModel();
...
listModel.addListDataListener(new MyListDataListener());

class MyListDataListener implements ListDataListener {
    public void contentsChanged(ListDataEvent e) {
        log.append("contentsChanged: " + e.getIndex0() +
                   ", " + e.getIndex1() + newline);
    }
    public void intervalAdded(ListDataEvent e) {
        log.append("intervalAdded: " + e.getIndex0() +
                   ", " + e.getIndex1() + newline);
    }
    public void intervalRemoved(ListDataEvent e) {
        log.append("intervalRemoved: " + e.getIndex0() +
                   ", " + e.getIndex1() + newline);
    }
} 

列表数据监听器 API

列表数据监听器接口

ListDataListener 没有对应的适配器类。

方法 目的
intervalAdded(ListDataEvent) 当一个或多个项目被添加到列表时调用。
intervalRemoved(ListDataEvent) 当一个或多个项目从列表中被移除时调用。
contentsChanged(ListDataEvent) 当列表中一个或多个项目的内容发生更改时调用。

ListDataEvent API

方法 目的
Object getSource() (java.util.EventObject) 返回触发事件的对象。
int getIndex0() 返回值发生更改的第一个项目的索引。
int getIndex1() 返回值发生更改的最后一个项目的索引。
int getType() 返回事件类型。可能的值为:CONTENTS_CHANGEDINTERVAL_ADDEDINTERVAL_REMOVED

使用列表数据监听器的示例

下表列出了使用列表数据监听器的示例。

示例 描述位置 备注
ListDataEventDemo 本节 报告列表上发生的所有列表数据事件。

如何编写列表选择监听器

原文:docs.oracle.com/javase/tutorial/uiswing/events/listselectionlistener.html

列表选择事件发生在 列表 或 表格 中的选择正在更改或刚刚更改时。列表选择事件是从实现 ListSelectionModel 接口的对象中触发的。要获取表格的列表选择模型对象,可以使用 getSelectionModel 方法或 getColumnModel().getSelectionModel()

要检测列表选择事件,您需要在适当的列表选择模型对象上注册监听器。JList 类还提供了在列表本身上注册监听器的选项,而不是直接在列表选择模型上注册。

本节将介绍两个示例,展示如何监听选择模型上的列表选择事件。使用列表选择监听器的示例 列出了直接在列表上监听的示例。

在这两个示例中,您可以动态更改选择模式为三种支持的模式之一:

  • 单选模式

  • 单区间选择模式

  • 多区间选择模式

这是 ListSelectionDemo 示例在列表中运行的图片:


试一试:

  1. 点击"启动"按钮以使用 Java™ Web Start 运行 ListSelectionDemo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考 示例索引。

  2. 选择和取消列表中的项目。选择项目所需的鼠标和键盘命令取决于外观。对于 Java 外观,单击左鼠标按钮开始选择,使用 shift 键连续扩展选择,使用 control 键不连续扩展选择。请注意,有两种类型的选择:Lead 和 Anchor。Lead 是焦点项目,Anchor 是高亮项目。当您按下 ctrl 键并上下移动时,Lead 选择会导致事件被触发,即使实际选择没有改变。拖动鼠标会根据列表选择模式移动或扩展选择。


这是 TableListSelectionDemo 示例在表格中运行的图片:


试试这个:

  1. 点击"启动"按钮以使用Java™ Web Start运行 TableListSelectionDemo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。

  2. 在表格中选择和取消选择项目。选择项目所需的鼠标和键盘命令取决于外观。对于 Java 外观,单击左鼠标按钮开始选择,使用 Shift 键连续扩展选择,使用 Control 键不连续扩展选择。请注意,有两种类型的选择:Lead 和 Anchor。Lead 是焦点项目,Anchor 是突出显示的项目。当按下 ctrl 键并向上或向下移动时,主选择会导致事件被触发,即使实际选择没有更改。拖动鼠标会移动或扩展选择,具体取决于列表选择模式。


您可以在ListSelectionDemo.java中找到 ListSelectionDemo 的整个程序,以及在TableListSelectionDemo.java中找到 TableListSelectionDemo 的整个程序。

这是设置选择模型并向其添加监听器的ListSelectionDemo中的代码:

java 复制代码
*...//where the member variables are defined*
JList list;
    *...//in the init method:*
    listSelectionModel = list.getSelectionModel();
    listSelectionModel.addListSelectionListener(
                            new SharedListSelectionHandler());
    ...

这是适用于所有可能的选择模式的监听器代码:

java 复制代码
class SharedListSelectionHandler implements ListSelectionListener {
    public void valueChanged(ListSelectionEvent e) {
        ListSelectionModel lsm = (ListSelectionModel)e.getSource();

        int firstIndex = e.getFirstIndex();
        int lastIndex = e.getLastIndex();
        boolean isAdjusting = e.getValueIsAdjusting();
        output.append("Event for indexes "
                      + firstIndex + " - " + lastIndex
                      + "; isAdjusting is " + isAdjusting
                      + "; selected indexes:");

        if (lsm.isSelectionEmpty()) {
            output.append(" <none>");
        } else {
            // Find out which indexes are selected.
            int minIndex = lsm.getMinSelectionIndex();
            int maxIndex = lsm.getMaxSelectionIndex();
            for (int i = minIndex; i <= maxIndex; i++) {
                if (lsm.isSelectedIndex(i)) {
                    output.append(" " + i);
                }
            }
        }
        output.append(newline);
    }
}

这个valueChanged方法显示了事件报告的第一个和最后一个索引,事件的isAdjusting标志的值,以及当前选定的索引。

请注意,事件报告的第一个和最后一个索引指示了选择已更改的项目的包含范围。如果选择模式是多区间选择,则范围内的某些项目可能未更改。如果用户仍在操作选择,则isAdjusting标志为true,如果用户已完成更改选择,则为false

传递给valueChangedListSelectionEvent对象仅指示选择已更改。事件不包含有关当前选择的任何信息。因此,此方法查询选择模型以确定当前选择。

列表选择监听器 API

列表选择监听器接口

因为ListSelectionListener只有一个方法,所以没有相应的适配器类。

方法 目的
valueChanged(ListSelectionEvent) 响应选择更改时调用。

ListSelectionEvent API

方法 目的
Object getSource() (java.util.EventObject) 返回触发事件的对象。如果直接在列表上注册列表选择监听器,则每个事件的源是列表。否则,源是选择模型。
int getFirstIndex() 返回选择值已更改的第一项的索引。请注意,对于多个间隔选择,保证第一个和最后一个项目已更改,但它们之间的项目可能没有更改。但是,当您按下 ctrl 键并向上或向下移动时,主选择会导致事件被触发,即使实际选择没有更改。
int getLastIndex() 返回选择值已更改的最后一项的索引。请注意,对于多个间隔选择,保证第一个和最后一个项目已更改,但它们之间的项目可能没有更改。但是,当您按下 ctrl 键并上下移动时,主选择会导致事件被触发,即使实际选择没有更改。
boolean getValueIsAdjusting() 如果选择仍在更改,则返回true。许多列表选择监听器仅对选择的最终状态感兴趣,并且可以在此方法返回true时忽略列表选择事件。

使用列表选择监听器的示例

下表列出了使用列表选择监听器的示例。

示例 描述位置 备注
ListSelectionDemo 本节 报告列表上发生的所有列表选择事件。允许用户动态更改选择模式。
TableListSelectionDemo 本节 报告表上发生的所有列表选择事件。允许用户动态更改选择模式。
ListDemo 如何使用列表 监听单选列表上的事件(而不是其选择模型)。根据列表中是否选择了任何项目来启用或禁用按钮。
SplitPaneDemo 如何使用列表 监听单选列表上的事件(而不是其选择模型)。
SimpleTableSelectionDemo 如何使用表格 在一个表格上使用两种不同的列表选择监听器。一个监听器监听表格列上的列表选择事件,另一个监听器监听表格行上的列表选择事件。

如何编写鼠标监听器

原文:docs.oracle.com/javase/tutorial/uiswing/events/mouselistener.html

鼠标事件通知用户使用鼠标(或类似输入设备)与组件交互时发生。鼠标事件发生在光标进入或退出组件的屏幕区域时,以及用户按下或释放鼠标按钮时。

跟踪光标的移动比跟踪其他鼠标事件需要更多的系统开销。这就是为什么鼠标移动事件被分为鼠标移动监听器类型(参见如何编写鼠标移动监听器)。

要跟踪鼠标滚轮事件,您可以注册一个鼠标滚轮监听器。有关更多信息,请参阅如何编写鼠标滚动监听器。

如果应用程序需要检测鼠标事件和鼠标移动事件,请使用MouseInputAdapter类。该类实现了MouseInputListener,这是一个方便的接口,实现了MouseListenerMouseMotionListener接口。但是,MouseInputListener接口不实现MouseWheelListener接口。

或者,使用相应的 AWT MouseAdapter 类,该类实现了MouseListenerMouseMotionListenerMouseWheelListener接口。

以下示例显示了一个鼠标监听器。窗口顶部是一个空白区域(由名为BlankArea的类实现)。鼠标监听器同时监听BlankArea和其容器MouseEventDemo的事件。每次发生鼠标事件时,在空白区域下方显示一个描述性消息。通过将光标移动到空白区域上方并偶尔按下鼠标按钮,您可以触发鼠标事件。


试试这个:

  1. 点击"启动"按钮以使用Java™ Web Start运行 MouseEventDemo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。

  2. 将光标移动到窗口顶部的黄色矩形中。

    您将看到一个或多个鼠标进入事件。

  3. 按住左鼠标按钮不要移动鼠标。

    你会看到一个鼠标按下事件。你可能会看到一些额外的鼠标事件,比如鼠标退出然后鼠标进入。

  4. 释放鼠标按钮。

    你会看到一个鼠标释放事件。如果你没有移动鼠标,将会接着是一个鼠标点击事件。

  5. 再次按住鼠标按钮,然后拖动鼠标,使光标最终移出窗口。释放鼠标按钮。

    你会看到一个鼠标按下事件,接着是一个鼠标退出事件,然后是一个鼠标释放事件。你不会收到有关光标移动的通知。要获取鼠标移动事件,你需要实现一个鼠标移动监听器。


你可以在MouseEventDemo.javaBlankArea.java中找到演示代码。这里是演示的鼠标事件处理代码:

java 复制代码
public class MouseEventDemo ... implements MouseListener {
        *//where initialization occurs:*
        //Register for mouse events on blankArea and the panel.
        blankArea.addMouseListener(this);
        addMouseListener(this);
    ...

    public void mousePressed(MouseEvent e) {
       saySomething("Mouse pressed; # of clicks: "
                    + e.getClickCount(), e);
    }

    public void mouseReleased(MouseEvent e) {
       saySomething("Mouse released; # of clicks: "
                    + e.getClickCount(), e);
    }

    public void mouseEntered(MouseEvent e) {
       saySomething("Mouse entered", e);
    }

    public void mouseExited(MouseEvent e) {
       saySomething("Mouse exited", e);
    }

    public void mouseClicked(MouseEvent e) {
       saySomething("Mouse clicked (# of clicks: "
                    + e.getClickCount() + ")", e);
    }

    void saySomething(String eventDescription, MouseEvent e) {
        textArea.append(eventDescription + " detected on "
                        + e.getComponent().getClass().getName()
                        + "." + newline);
    }
}

鼠标监听器 API

鼠标监听器接口

方法 目的
mouseClicked(MouseEvent) 在用户点击监听组件后立即调用。
mouseEntered(MouseEvent) 在光标进入监听组件边界后立即调用。
mouseExited(MouseEvent) 在光标退出监听组件边界后立即调用。
mousePressed(MouseEvent) 在光标位于监听组件上方时用户按下鼠标按钮后立即调用。
mouseReleased(MouseEvent) 在鼠标按下监听组件后释放鼠标按钮后立即调用。

MouseAdapter 类(AWT 适配器类)是抽象的。它的所有方法都是空的。因此开发人员可以为特定于应用程序的事件定义方法。你也可以使用MouseInputAdapter 类,它具有从MouseListenerMouseMotionListener中可用的所有方法。

鼠标事件类

方法 目的
int getClickCount() 返回用户连续快速点击的次数(包括此事件)。例如,双击返回 2。

| int getX() int getY()

Point getPoint() | 返回事件发生的(x,y)位置,相对于触发事件的组件。

| int getXOnScreen() int getYOnScreen()

int getLocationOnScreen() | 返回事件的绝对(x,y)位置。这些坐标是相对于多屏环境的虚拟坐标系。否则,这些坐标是相对于与组件的图形配置相关联的坐标系。

int getButton() 返回已更改状态的鼠标按钮(如果有)。返回以下常量之一:NOBUTTONBUTTON1BUTTON2BUTTON3
boolean isPopupTrigger() 如果鼠标事件应该引起弹出菜单出现,则返回true。因为弹出触发器是平台相关的,如果您的程序使用弹出菜单,您应该为所有可以出现弹出菜单的组件触发的所有鼠标按下和鼠标释放事件调用isPopupTrigger。有关弹出菜单的更多信息,请参见弹出菜单。
String getMouseModifiersText(int) 返回描述事件期间活动的修改键和鼠标按钮的String,例如"Shift"或"Ctrl+Shift"。这些字符串可以使用 awt.properties 文件进行本地化。

InputEvent

MouseEvent 类从InputEvent类继承了许多有用的方法,还从ComponentEventAWTEvent类中继承了一些方便的方法。

方法 目的
int getID() (java.awt.AWTEvent) 返回事件类型,定义了特定的操作。例如,MouseEvent id 反映了每个鼠标事件的鼠标按钮状态。MouseEvent id 可以指定以下状态:MouseEvent.MOUSE_PRESSEDMouseEvent.MOUSE_RELEASEDMouseEvent.MOUSE_CLICKED
Component getComponent()ComponentEvent 返回触发事件的组件。您可以使用此方法代替 getSource 方法。
int getWhen() 返回事件发生时的时间戳。时间戳越高,事件发生的时间越近。

| boolean isAltDown() boolean isControlDown()

boolean isMetaDown()

boolean isShiftDown()

返回事件触发时各个修改键的状态。

| int getModifiers() | 返回事件触发时所有修改键和鼠标按钮的状态。您可以使用此方法确定鼠标事件触发时按下(或释放)了哪个鼠标按钮。InputEvent 类为 getModifiers 方法定义了以下常量:ALT_MASKBUTTON1_MASKBUTTON2_MASKBUTTON3_MASKCTRL_MASKMETA_MASKSHIFT_MASK。例如,如果按下了右键,则以下表达式为真:

java 复制代码
(mouseEvent.getModifiers() & InputEvent.BUTTON3_MASK)
== InputEvent.BUTTON3_MASK

|

| int getModifiersEx() | 返回此事件的扩展修改器掩码。扩展修改器表示鼠标按钮和所有模态键(如 ALT、CTRL、META)在事件发生后的状态。您可以使用以下预定义位掩码之一来检查修改器的状态:SHIFT_DOWN_MASKCTRL_DOWN_MASKMETA_DOWN_MASKALT_DOWN_MASKBUTTON1_DOWN_MASKBUTTON2_DOWN_MASKBUTTON3_DOWN_MASKALT_GRAPH_DOWN_MASK。例如,要检查按钮 1 是否按下,但按钮 2 和按钮 3 没有按下,您可以使用以下代码片段:

java 复制代码
if (event.getModifiersEx() & (BUTTON1_DOWN_MASK &#124;
                              BUTTON2_DOWN_MASK &#124;
                              BUTTON3_DOWN_MASK)
                               == BUTTON1_DOWN_MASK) {
    ...
}

|

int getModifiersExText(int) 返回描述扩展修改键和鼠标按钮的字符串,如 "Shift"、"Button1" 或 "Ctrl+Shift"。这些字符串可以通过更改 awt.properties 文件进行本地化。

鼠标信息类

MouseInfo 类提供了在应用程序运行时随时获取鼠标指针位置信息的方法。

方法 目的
getPointerInfo() 返回一个代表鼠标指针当前位置的PointerInfo实例。
getNumberOfButtons() 返回鼠标上的按钮数量,如果系统不支持鼠标则返回-1

使用鼠标监听器的示例

下表列出了使用鼠标监听器的示例。

示例 描述位置 注释
MouseEventDemo 本节 报告在空白面板内发生的所有鼠标事件,以演示触发鼠标事件的情况。
GlassPaneDemo 如何使用根窗格 使用MouseInputAdapter的子类来监听根窗格的玻璃窗格上的鼠标事件和鼠标移动事件。重新分派事件给底层组件。
TableSortDemo 如何使用表格 监听表头上的鼠标事件。对所选列中的数据进行排序。
PopupMenuDemo 如何使用菜单 在鼠标点击时显示弹出菜单。
TrackFocusDemo 如何使用焦点子系统 自定义组件Picture实现了一个鼠标监听器,当用户点击组件时请求焦点。

如何编写鼠标移动监听器

原文:docs.oracle.com/javase/tutorial/uiswing/events/mousemotionlistener.html

鼠标移动事件通知用户使用鼠标(或类似输入设备)移动屏幕上的光标。有关监听其他类型鼠标事件(如点击)的信息,请参阅如何编写鼠标监听器。有关监听鼠标滚轮事件的信息,请参阅如何编写鼠标滚轮监听器。

如果应用程序需要检测鼠标事件和鼠标移动事件,可以使用MouseInputAdapter类,该类实现了MouseInputListener一个方便的接口,实现了MouseListenerMouseMotionListener接口。

或者,使用相应的MouseAdapter AWT 类,该类实现了MouseMotionListener接口,以创建一个MouseMotionEvent并重写特定事件的方法。

以下演示代码包含一个鼠标移动监听器。这个演示与如何编写鼠标监听器部分描述的演示完全相同,只是用MouseMotionListener接口替换了MouseListener接口。此外,MouseMotionEventDemo 实现了mouseDraggedmouseMoved方法,而不是鼠标监听器方法,并显示坐标而不是点击次数。


试试看:

  1. 点击"启动"按钮以运行 MouseMotionEventDemo,使用Java™ Web Start下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。

  2. 将光标移入窗口顶部的黄色矩形中。

    你将看到一个或多个鼠标移动事件。

  3. 按住鼠标按钮,然后移动鼠标,使光标移出黄色矩形。

    你将看到鼠标拖动事件。


您可以在 MouseMotionEventDemo.javaBlankArea.java 中找到演示代码。以下来自 MouseMotionEventDemo 的代码片段实现了鼠标移动事件处理:

java 复制代码
public class MouseMotionEventDemo extends JPanel 
                                  implements MouseMotionListener {
    *//...in initialization code:*
        //Register for mouse events on blankArea and panel.
        blankArea.addMouseMotionListener(this);
        addMouseMotionListener(this);
        ...
    }

    public void mouseMoved(MouseEvent e) {
       saySomething("Mouse moved", e);
    }

    public void mouseDragged(MouseEvent e) {
       saySomething("Mouse dragged", e);
    }

    void saySomething(String eventDescription, MouseEvent e) {
        textArea.append(eventDescription 
                        + " (" + e.getX() + "," + e.getY() + ")"
                        + " detected on "
                        + e.getComponent().getClass().getName()
                        + newline);
    }
}

SelectionDemo 示例,绘制一个矩形来说明用户当前的拖动。为了绘制矩形,应用程序必须实现三种类型的鼠标事件的事件处理程序:鼠标按下、鼠标拖动和鼠标释放。为了被所有这些事件通知,处理程序必须同时实现 MouseListenerMouseMotionListener 接口,并且注册为鼠标监听器和鼠标移动监听器。为了避免定义空方法,处理程序不直接实现任何监听器接口。相反,它扩展了 MouseInputAdapter,如下面的代码片段所示。

java 复制代码
*...//where initialization occurs:*
    MyListener myListener = new MyListener();
    addMouseListener(myListener);
    addMouseMotionListener(myListener);
...
private class MyListener extends MouseInputAdapter {
    public void mousePressed(MouseEvent e) {
        int x = e.getX();
        int y = e.getY();
        currentRect = new Rectangle(x, y, 0, 0);
        updateDrawableRect(getWidth(), getHeight());
        repaint();
    }

    public void mouseDragged(MouseEvent e) {
        updateSize(e);
    }

    public void mouseReleased(MouseEvent e) {
        updateSize(e);
    }

    void updateSize(MouseEvent e) {
        int x = e.getX();
        int y = e.getY();
        currentRect.setSize(x - currentRect.x,
                            y - currentRect.y);
        updateDrawableRect(getWidth(), getHeight());
        Rectangle totalRepaint = rectToDraw.union(previouseRectDrawn); 
        repaint(totalRepaint.x, totalRepaint.y,
                totalRepaint.width, totalRepaint.height);
    }
}

鼠标移动监听器 API

鼠标移动监听器接口

相应的适配器类是 MouseMotionAdapterMouseAdapter

方法 目的
mouseDragged(MouseEvent) 当用户按住鼠标按钮移动鼠标时调用。即使光标不再位于该组件上,此事件也由最近触发鼠标按下事件的组件触发。
mouseMoved(MouseEvent) 当用户移动鼠标而没有按下鼠标按钮时调用。此事件由当前位于光标下的组件触发。

每个鼠标移动事件方法都有一个参数 ------ 并且 叫做 MouseMotionEvent!相反,每个鼠标移动事件方法使用一个 MouseEvent 参数。有关使用 MouseEvent 对象的信息,请参阅鼠标事件 API。

使用鼠标移动监听器的示例

以下表格列出了使用鼠标移动监听器的示例。

示例 描述位置 备注
MouseMotionEventDemo 此部分 报告在空白面板内发生的所有鼠标移动事件,以展示触发鼠标移动事件的情况。
LayeredPaneDemoLayeredPaneDemo2 如何使用分层窗格 在响应鼠标移动事件时,在分层窗格内移动杜克的图像。
SelectionDemo 允许用户拖动矩形选择图像的一部分。使用 MouseInputAdapter 的子类监听鼠标事件和鼠标移动事件。
GlassPaneDemo 如何使用根窗格 使用 MouseInputAdapter 的子类监听根窗格的玻璃窗格上的鼠标事件和鼠标移动事件。重新分派事件给底层组件。
ScrollDemo 如何使用滚动窗格 标签子类 ScrollablePicture 使用鼠标移动监听器,允许用户在将光标拖出窗口时滚动图片。

如何编写鼠标滚轮监听器

原文:docs.oracle.com/javase/tutorial/uiswing/events/mousewheellistener.html

鼠标滚轮事件会在鼠标滚轮旋转时通知。有关监听其他鼠标事件(如点击)的信息,请参阅如何编写鼠标监听器。有关监听鼠标拖动事件的信息,请参阅如何编写鼠标移动监听器。并非所有鼠标都配备鼠标滚轮,在这种情况下,将不会生成鼠标滚轮事件。无法通过编程方式检测鼠标是否配备鼠标滚轮。

或者,使用相应的MouseAdapter AWT 类,该类实现了MouseWheelListener接口,以创建MouseWheelEvent并重写特定事件的方法。

通常不需要实现鼠标滚轮监听器,因为鼠标滚轮主要用于滚动。滚动窗格会自动注册鼠标滚轮监听器,以适当地响应鼠标滚轮。

但是,要创建一个自定义组件用于滚动窗格内部,您可能需要自定义其滚动行为 ------ 具体来说,您可能需要设置单位和块增量。例如,对于文本区域,滚动一个单位意味着滚动一行文本。块增量通常会滚动整个"页面"或视口的大小。有关更多信息,请参阅实现滚动智能客户端页面中的如何使用滚动窗格。

要生成鼠标滚轮事件,光标必须位于已注册监听鼠标滚轮事件的组件上方 。发生的滚动类型,无论是WHEEL_UNIT_SCROLL还是WHEEL_BLOCK_SCROLL,都取决于平台。鼠标滚轮滚动的量也取决于平台。滚动的类型和量都可以通过平台的鼠标控制面板进行设置。

以下示例演示了鼠标滚轮事件。


试试这个:

  1. 单击"启动"按钮以使用Java™ Web Start运行 MouseWheelEventDemo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参阅示例索引。

  2. 将光标移动到文本区域上。

  3. 将鼠标滚轮远离您。您将看到一个或多个鼠标滚轮事件向方向。

  4. 将鼠标滚轮向相反方向旋转。您将看到鼠标滚轮事件向方向。

  5. 尝试更改系统的鼠标控制面板中鼠标滚轮的滚动行为,看看输出如何变化。您不需要重新启动演示以使更改生效。


对于其鼠标滚轮使用单位增量的系统的 MouseWheelEventDemo 的输出可能如下所示:

java 复制代码
javax.swing.JTextArea: Mouse wheel moved UP 1 notch(es)
    Scroll type: WHEEL_UNIT_SCROLL
    Scroll amount: 3 unit increments per notch
    Units to scroll: -3 unit increments
    Vertical unit increment: 16 pixels

getScrollAmount方法返回的滚动量指示将滚动多少个单位,并始终呈现正数。由getUnitsToScroll方法返回的滚动单位在向下滚动时为正,在向上滚动时为负。垂直单位的像素数是使用getUnitIncrement方法从垂直滚动条获取的。在前面的示例中,向上滚动鼠标滚轮一个刻度应导致文本区域向上滚动 48 像素(3x16)。

对于使用块增量进行鼠标滚轮滚动的系统,对于鼠标滚轮的相同移动,输出可能如下所示:

java 复制代码
javax.swing.JTextArea: Mouse wheel moved UP 1 notch(es)
    Scroll type: WHEEL_BLOCK_SCROLL
    Vertical block increment: 307 pixels

垂直块增量是使用getBlockIncrement方法从垂直滚动条获取的。在这种情况下,向上滚动鼠标滚轮一个刻度意味着文本区域应向上滚动 307 像素。

MouseWheelEventDemo.java文件中找到演示的代码。以下代码片段与鼠标滚轮事件处理相关:

java 复制代码
public class MouseWheelEventDemo ... implements MouseWheelListener ... {
    public MouseWheelEventDemo() {
        *//where initialization occurs:*
        //Register for mouse-wheel events on the text area.
        textArea.addMouseWheelListener(this);
        ...
    }

    public void mouseWheelMoved(MouseWheelEvent e) {
       String message;
       int notches = e.getWheelRotation();
       if (notches < 0) {
           message = "Mouse wheel moved UP "
                        + -notches + " notch(es)" + newline;
       } else {
           message = "Mouse wheel moved DOWN "
                        + notches + " notch(es)" + newline;
       }
       if (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL) {
           message += "    Scroll type: WHEEL_UNIT_SCROLL" + newline;
           message += "    Scroll amount: " + e.getScrollAmount()
                   + " unit increments per notch" + newline;
           message += "    Units to scroll: " + e.getUnitsToScroll()
                   + " unit increments" + newline;
           message += "    Vertical unit increment: "
               + scrollPane.getVerticalScrollBar().getUnitIncrement(1)
               + " pixels" + newline;
       } else { //scroll type == MouseWheelEvent.WHEEL_BLOCK_SCROLL
           message += "    Scroll type: WHEEL_BLOCK_SCROLL" + newline;
           message += "    Vertical block increment: "
               + scrollPane.getVerticalScrollBar().getBlockIncrement(1)
               + " pixels" + newline;
       }
       saySomething(message, e);
    }
    ...
}

鼠标滚轮监听器 API

鼠标滚轮监听器接口

尽管MouseWheelListener只有一个方法,但它有相应的适配器类------MouseAdapter。这种能力使应用程序只需一个适配器类实例来管理来自鼠标指针的所有类型的事件。

方法 目的
mouseWheelMoved(MouseWheelEvent) 当鼠标滚轮旋转时调用。

鼠标滚轮事件类

方法 目的
int getScrollType() 返回要使用的滚动类型。可能的值为WHEEL_BLOCK_SCROLLWHEEL_UNIT_SCROLL,由本机平台确定。
int getWheelRotation() 返回鼠标滚轮旋转的刻度数。如果鼠标滚轮朝向用户(向下)旋转,则值为正。如果鼠标滚轮远离用户(向上)旋转,则值为负。
int getScrollAmount() 返回每个刻度应滚动的单位数。这始终是一个正数,并且仅在滚动类型为MouseWheelEvent.WHEEL_UNIT_SCROLL时有效。
int getUnitsToScroll() 返回当前事件应滚动的正负单位数。仅在滚动类型为MouseWheelEvent.WHEEL_UNIT_SCROLL时有效。

使用鼠标滚轮监听器的示例

下表列出了使用鼠标滚轮监听器的示例。

示例 描述位置 备注
MouseWheelEventDemo 本节 报告在文本区域内发生的所有鼠标滚轮事件,以展示触发鼠标滚轮事件的情况。

如何编写属性更改侦听器

原文:docs.oracle.com/javase/tutorial/uiswing/events/propertychangelistener.html

每当bean (符合 JavaBeans™规范的组件)的bound property的值更改时,都会触发属性更改事件。您可以从 Java 教程的 JavaBeans trail 中了解更多关于 beans 的信息。所有 Swing 组件也都是 beans。

一个 JavaBeans 属性通过其getset 方法访问。例如,JComponent具有font 属性,可以通过getFontsetFont方法访问。

除了getset方法外,绑定属性在其值更改时会触发属性更改事件。有关更多信息,请参阅 JavaBeans trail 中的 Bound Properties 页面。

一些常常需要属性更改侦听器的场景包括:

  • 您已经实现了一个格式化文本字段,并且需要一种方法来检测用户何时输入了新值。您可以在格式化文本字段上注册一个属性更改侦听器,以侦听value 属性的更改。请参阅 How to Use Formatted Text Fields 中的FormattedTextFieldDemo示例。

  • 您已经实现了一个对话框,并且需要知道用户何时单击了对话框的按钮或更改了对话框中的选择。请参阅 How to Make Dialogs 中的DialogDemo示例,了解如何在选项面板上注册属性更改侦听器以侦听value 属性的更改。您还可以查看 How to Use File Choosers 中的FileChooserDemo2示例,了解如何注册属性更改侦听器以侦听directoryChangedselectedFileChanged属性的更改。

  • 您需要在具有焦点的组件更改时收到通知。您可以在键盘焦点管理器上注册一个属性更改侦听器,以侦听focusOwner 属性的更改。请参阅 How to Use the Focus Subsystem 中的TrackFocusDemoDragPictureDemo示例。

尽管这些是属性更改侦听器的一些常见用途,但您可以在符合 JavaBeans 规范的任何组件的绑定属性上注册属性更改侦听器。

您可以通过两种方式注册属性更改侦听器。第一种使用addPropertyChangeListener(PropertyChangeListener)方法。当以这种方式注册侦听器时,您将收到有关该对象的每个绑定属性的每次更改的通知。在propertyChange方法中,您可以使用PropertyChangeEventgetPropertyName方法获取已更改的属性的名称,如以下代码片段所示:

java 复制代码
KeyboardFocusManager focusManager =
   KeyboardFocusManager.getCurrentKeyboardFocusManager();
focusManager.addPropertyChangeListener(new FocusManagerListener());
...
public FocusManagerListener implements PropertyChangeListener {
    public void propertyChange(PropertyChangeEvent e) {
        String propertyName = e.getPropertyName();
        if ("focusOwner".equals(propertyName) {
            ...
        } else if ("focusedWindow".equals(propertyName) {
            ...
        }
    }
    ...
}

第二种注册属性更改监听器的方法使用了方法 addPropertyChangeListener(String, PropertyChangeListener)String 参数是属性的名称。使用这种方法意味着只有在特定属性发生更改时才会收到通知。例如,如果你像这样注册了一个属性更改监听器:

java 复制代码
aComponent.addPropertyChangeListener("font",
                                     new FontListener());

FontListener 只有在组件的 font 属性值更改时才会收到通知。它 不会transferHandleropaqueborder 或任何其他属性值更改时收到通知。

以下示例展示了如何使用 addPropertyChangeListener 的两个参数版本在格式化文本字段的 value 属性上注册属性更改监听器:

java 复制代码
*//...where initialization occurs:*
double amount;
JFormattedTextField amountField;
...
amountField.addPropertyChangeListener("value",
                                      new FormattedTextFieldListener());
...
class FormattedTextFieldListener implements PropertyChangeListener {
    public void propertyChanged(PropertyChangeEvent e) {
        Object source = e.getSource();
        if (source == amountField) {
            amount = ((Number)amountField.getValue()).doubleValue();
            ...
        }
        *...//re-compute payment and update field...*
    }
}

属性更改监听器 API

注册 PropertyChangeListener

方法 目的
addPropertyChangeListener(PropertyChangeListener) 向监听器列表中添加一个属性更改监听器。
addPropertyChangeListener(String, PropertyChangeListener) 为特定属性添加属性更改监听器。只有当指定属性发生更改时才会调用监听器。

PropertyChangeListener 接口

因为 PropertyChangeListener 只有一个方法,所以没有相应的适配器类。

方法 目的
propertyChange(PropertyChangeEvent) 当被监听的 bean 更改绑定属性时调用。

PropertyChangeEvent

方法 目的
Object getNewValue() Object getOldValue() 分别返回属性的新值或旧值。
String getPropertyName() 返回已更改的属性的名称。
void setPropagationId() 获取或设置传播 ID 值。保留供将来使用。

使用属性更改监听器的示例

以下表格列出了使用属性更改监听器的示例。

示例 描述位置 备注
FormattedTextFieldDemo 如何使用格式化文本字段 在多个格式化文本字段上注册了属性更改监听器,以跟踪 value 属性的更改。
DialogDemo 如何创建对话框 CustomDialog类在选项面板上注册属性更改监听器,以监听valueinputValue属性的变化。
FileChooserDemo2 如何使用文件选择器 ImagePreview类在文件选择器上注册属性更改监听器,以监听directoryChangedselectedFileChanged属性的变化。
TrackFocusDemo 如何使用焦点子系统 在键盘焦点管理器上注册属性更改监听器以跟踪focusOwner属性的变化。

如何编写表模型监听器

原文:docs.oracle.com/javase/tutorial/uiswing/events/tablemodellistener.html

在实例化时,每个JTable对象都传递一个管理其显示数据的表模型对象。如果没有指定自定义的TableModel对象,默认情况下,JTable对象继承一个DefaultTable对象,但默认情况下,此模型仅管理字符串。要处理对象、执行计算或从数据库或其他程序检索数据,必须设计自己的自定义TableModel对象,该对象实现TableModel接口。详细信息请参见创建表模型。

要检测表模型对象管理的数据的更改,JTable类需要实现TableModelListener接口,调用addTableModelListener()来捕获事件,然后重写tableChanged()来响应监听器事件。详细信息请参见监听数据更改。

表模型监听器 API

TableModelListener 接口

因为TableModelListener只有一个方法,所以没有相应的适配器类。

方法 目的
tableChanged(TableModelEvent) 当表的结构或数据发生更改时调用。

TableModelEvent API

方法 目的
Object getSource()java.util.EventObject 返回触发事件的对象。
int getFirstRow() 返回更改的第一行的索引。TableModelEvent.HEADER_ROW指定表头。
int getLastRow() 更改的最后一行。同样,HEADER_ROW是可能的值。
int getColumn() 返回更改的列的索引。常量TableModelEvent.ALL_COLUMNS指定所有列可能已更改。
int getType() 更改的单元格发生了什么。返回值是以下之一:TableModelEvent.INSERTTableModelEvent.DELETETableModelEvent.UPDATE

如何编写树展开监听器

原文:docs.oracle.com/javase/tutorial/uiswing/events/treeexpansionlistener.html

有时在使用树时,您可能需要在分支展开或折叠时做出反应。例如,您可能需要加载或保存数据。

有两种监听器报告展开和折叠事件:树展开 监听器和树将展开 监听器。本页讨论树展开监听器。有关树将展开监听器的描述,请参阅如何编写树将展开监听器。

树展开监听器会检测展开或折叠是否已经发生。一般来说,除非需要阻止展开或折叠发生,否则应该实现树展开监听器。

本示例演示了一个简单的树展开监听器。窗口底部的文本区域在每次发生树展开事件时显示一条消息。这是一个直接简单的演示。要查看一个更有趣的版本,可以否决展开,请参阅如何编写树将展开监听器。


试试这个:

  1. 点击"启动"按钮以使用Java™ Web Start运行 TreeExpandEventDemo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。

  2. 展开一个节点。将触发树展开事件。

  3. 折叠节点。将触发树折叠事件。


以下代码显示了程序如何处理展开事件。您可以在TreeExpandEventDemo.java中找到此示例的源代码。

java 复制代码
public class TreeExpandEventDemo ... {
    ...
    void saySomething(String eventDescription, TreeExpansionEvent e) {
        textArea.append(eventDescription + "; "
                        + "path = " + e.getPath()
                        + newline);
    }

    class DemoArea ... implements TreeExpansionListener {
        ...
        public DemoArea() {
            ...
            tree.addTreeExpansionListener(this);
            ...
        }
        ...
        // Required by TreeExpansionListener interface.
        public void treeExpanded(TreeExpansionEvent e) {
            saySomething("Tree-expanded event detected", e);
        }

        // Required by TreeExpansionListener interface.
        public void treeCollapsed(TreeExpansionEvent e) {
            saySomething("Tree-collapsed event detected", e);
        }
    }
}

树展开监听器 API

TreeExpansionListener 接口

TreeExpansionListener没有适配器类。

方法 目的
treeCollapsed(TreeExpansionEvent) 在树节点折叠后调用。
treeExpanded(TreeExpansionEvent) 在树节点展开后调用。

TreeExpansionEvent API

方法 目的
Object getSource() 返回触发事件的对象。
TreePath getPath() 返回一个TreePath对象,该对象标识从树的根节点到折叠/展开节点的每个节点,包括它们自身。

使用树展开监听器的示例

下表列出了使用树展开监听器的示例。

示例 描述位置 备注
TreeExpandEventDemo 本节 每当发生树展开事件时显示一条消息。
TreeExpandEventDemo2 如何编写树展开监听器 TreeExpandEventDemo添加了一个树展开监听器。

如何编写树模型监听器

原文:docs.oracle.com/javase/tutorial/uiswing/events/treemodellistener.html

通过实现树模型监听器,您可以检测到由树显示的数据何时发生更改。您可以使用树模型监听器来检测用户何时编辑树节点。所有通知都描述相对于树中的节点的更改。有关详细信息,请阅读动态更改树。

树模型监听器 API

树模型监听器接口

TreeModelListener没有适配器类。

方法 目的
treeNodesChanged(TreeModelEvent) 当一个或多个兄弟节点以某种方式发生更改时调用。
treeNodesInserted(TreeModelEvent) 在节点插入到树中后调用。
treeNodesRemoved(TreeModelEvent) 在节点从树中移除后调用。
treeStructureChanged(TreeModelEvent) 在树的结构从当前节点开始发生重大变化后调用。此事件适用于与此节点连接的所有节点。

树模型事件 API

方法 目的
获取源对象 (java.util.EventObject) 返回触发事件的对象。
获取子索引 对于treeNodesChangedtreeNodesInsertedtreeNodesRemoved,分别返回更改、插入或删除的节点的索引。对于treeStructureChanged没有有用的返回。
获取子节点 返回与子索引对应的对象。
获取路径 返回更改、插入或删除节点的父节点的路径。对于treeStructureChanged,返回结构发生变化的节点下方的路径。
获取树路径 返回与getPath相同的内容,但作为TreePath对象。

使用树模型监听器的示例

下表列出了使用树展开监听器的示例。

示例 描述位置 备注
DynamicTreeDemo 如何使用树 DynamicTree 类实现了树模型监听器,以便检测用户何时编辑了节点的数据。

如何编写树选择监听器

原文:docs.oracle.com/javase/tutorial/uiswing/events/treeselectionlistener.html

要检测用户何时在 树 中选择节点,需要注册树选择监听器。以下是一个示例,取自 响应节点选择 中讨论的 TreeDemo 示例,用于检测一次最多可以选择一个节点的树中的节点选择:

java 复制代码
tree.addTreeSelectionListener(new TreeSelectionListener() {
    public void valueChanged(TreeSelectionEvent e) {
        DefaultMutableTreeNode node = (DefaultMutableTreeNode)
                           tree.getLastSelectedPathComponent();

   */* if nothing is selected */* 
        if (node == null) return;

   */* retrieve the node that was selected */* 
        Object nodeInfo = node.getUserObject();
        ...
   * /* React to the node selection. */*
        ...
    }
});

要指定树应支持单选,程序使用以下代码:

java 复制代码
tree.getSelectionModel().setSelectionMode
        (TreeSelectionModel.SINGLE_TREE_SELECTION);

TreeSelectionModel 接口定义了三个选择模式的值:

DISCONTIGUOUS_TREE_SELECTION

这是默认树选择模型的默认模式。使用此模式,可以选择任意组合的节点。

SINGLE_TREE_SELECTION

这是前面示例中使用的模式。一次最多只能选择一个节点。

CONTIGUOUS_TREE_SELECTION

使用此模式,只能选择相邻行中的节点。

Tree Selection Listener API

TreeSelectionListener 接口

因为 TreeSelectionListener 只有一个方法,所以没有相应的适配器类。

方法 目的
valueChanged(TreeSelectionEvent) 每当选择更改时调用。

TreeSelectionEvent API

方法 目的
Object getSource() (java.util.EventObject) 返回触发事件的对象。
TreePath getNewLeadSelectionPath() 返回当前主导路径。
TreePath getOldLeadSelectionPath() 返回先前的主导路径。
TreePath getPath() 返回第一个路径元素。
TreePath[] getPaths() 返回已添加或移除的路径。
boolean isAddedPath() 如果第一个路径元素已添加到选择中,则返回 true。如果第一个路径已从选择中移除,则返回 false。
boolean isAddedPath(int) 如果指定索引的路径已添加到选择中,则返回 true。
boolean isAddedPath(TreePath) 如果指定的路径已添加到选择中,则返回 true。
Object getLastSelectedPathComponent() 返回当前选择中第一个节点中的最后路径组件。
TreePath getLeadSelectionPath() (JTree) 返回当前主导路径。

使用树选择监听器的示例

以下表格列出了使用树选择监听器的示例。

示例 描述位置 注释
TreeDemo 如何使用树 树监听器通过显示适当的 HTML 文档来响应节点点击。

如何编写树展开监听器

原文:docs.oracle.com/javase/tutorial/uiswing/events/treewillexpandlistener.html

树展开 监听器阻止树节点展开或折叠。要在展开或折叠发生后立即收到通知,应该使用树展开监听器

此演示向TreeExpandEventDemo示例中讨论的如何编写树展开监听器添加了一个树展开监听器。此处添加的代码演示了树展开监听器阻止节点展开和折叠:每次尝试展开节点时,监听器都会提示您确认。


试试这个:

  1. 点击"启动"按钮以使用Java™ Web Start运行 TreeExpandEventDemo2(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。

  2. 点击Potrero Hill节点左侧的图形。这告诉树你想要展开该节点。

    一个对话框出现,询问您是否真的要展开节点。

  3. 点击"展开"或关闭对话框。

    文本区域中的消息告诉您发生了树展开事件和树展开事件。每条消息的末尾都是展开节点的路径。

  4. 尝试展开另一个节点,但这次在对话框中按下"取消展开"按钮。

    节点不会展开。文本区域中的消息告诉您发生了树展开事件,并且您取消了树展开。

  5. 折叠Potrero Hill节点。

    节点在没有对话框出现的情况下折叠,因为事件处理程序的treeWillCollapse方法允许折叠发生,没有争议。


以下代码片段显示了此程序添加到TreeExpandEventDemo的代码。粗体行阻止了树展开的发生。您可以在TreeExpandEventDemo2.java中找到所有演示的源代码。

java 复制代码
public class TreeExpandEventDemo2 ... {
    ...
    class DemoArea ... implements ... TreeWillExpandListener {
        ...
        public DemoArea() {
            ...
            tree.addTreeWillExpandListener(this);
            ...
        }
        ...
        //Required by TreeWillExpandListener interface.
        public void treeWillExpand(TreeExpansionEvent e) 
                    throws ExpandVetoException {
            saySomething("Tree-will-expand event detected", e);
            *//...show a dialog...*
            if (*/* user said to cancel the expansion */*) {
                //Cancel expansion.
                saySomething("Tree expansion cancelled", e);
                throw new ExpandVetoException(e);
            }
        }

        //Required by TreeWillExpandListener interface.
        public void treeWillCollapse(TreeExpansionEvent e) {
            saySomething("Tree-will-collapse event detected", e);
        }
        ...
    }
}

树展开监听器 API

TreeWillExpandListener 接口

*TreeWillExpandListener没有适配器类。

方法 目的
treeWillCollapse(TreeExpansionEvent) 在树节点折叠之前调用。为了阻止折叠发生,你的方法实现应该抛出一个ExpandVetoException 事件。
treeWillExpand(TreeExpansionEvent) 在树节点展开之前调用。为了阻止展开发生,你的方法实现应该抛出一个ExpandVetoException 事件。

查看树展开事件 API 以获取有关前述方法的TreeExpansionEvent参数的信息。

使用树将展开监听器的示例

在本节中展示的TreeExpandEventDemo2是我们唯一使用树将展开监听器的示例。

如何编写可撤销编辑监听器

原文:docs.oracle.com/javase/tutorial/uiswing/events/undoableeditlistener.html

当组件上发生可撤销操作时,会触发可撤销编辑事件。目前,只有文本组件间接触发可撤销编辑事件。文本组件的文档会触发这些事件。对于文本组件,可撤销操作包括插入字符、删除字符和修改文本样式。程序通常监听可撤销编辑事件以帮助实现撤销和重做命令。

这是来自名为TextComponentDemo的应用程序的可撤销编辑事件处理代码。

java 复制代码
...
*//where initialization occurs*
*document*.addUndoableEditListener(new MyUndoableEditListener());
...
protected class MyUndoableEditListener implements UndoableEditListener {
    public void undoableEditHappened(UndoableEditEvent e) {
        //Remember the edit and update the menus
        undo.addEdit(e.getEdit());
        undoAction.updateUndoState();
        redoAction.updateRedoState();
    }
}  

您可以在使用 Swing 组件示例索引中找到TextComponentDemo的源文件链接。有关程序中可撤销编辑监听器方面的讨论,请参阅实现撤销和重做

可撤销编辑监听器 API

可撤销编辑监听器接口

因为UndoableEditListener只有一个方法,所以没有相应的适配器类。

方法 目的
undoableEditHappened(UndoableEditEvent) 当监听的组件上发生可撤销事件时调用。

可撤销编辑事件类

方法 目的
Object getSource() (java.util.EventObject) 返回触发事件的对象。
UndoableEdit getEdit() 返回一个表示发生的编辑并包含有关撤消或重做编辑的信息和命令的UndoableEdit对象。

使用可撤销编辑监听器的示例

以下表格列出了使用可撤销编辑监听器的示例。

示例 描述位置 备注
TextComponentDemo 实现撤销和重做 使用可撤销编辑监听器在文本窗格上实现撤销和重做。

如何编写窗口监听器

原文:docs.oracle.com/javase/tutorial/uiswing/events/windowlistener.html

本节解释了如何实现三种与窗口相关的事件处理程序:WindowListenerWindowFocusListenerWindowStateListener。所有三个监听器处理 WindowEvent 对象。所有三个事件处理程序中的方法都由抽象的 WindowAdapter 类实现。

当适当的监听器已在窗口(如框架或对话框)上注册时,窗口事件将在窗口活动或状态发生后立即触发。如果此窗口接收键盘输入,则将其视为"焦点所有者"。

以下窗口活动或状态可能在窗口事件之前发生:

  • 打开窗口 --- 第一次显示窗口。

  • 关闭窗口 --- 从屏幕上移除窗口。

  • 图标化窗口 --- 将窗口缩小为桌面上的图标。

  • 取消图标化窗口 --- 将窗口恢复到原始大小。

  • 焦点窗口 --- 包含"焦点所有者"的窗口。

  • 激活窗口(框架或对话框) --- 这个窗口要么是焦点窗口,要么拥有焦点窗口。

  • 非激活窗口 --- 这个窗口失去了焦点。有关焦点的更多信息,请参阅AWT 焦点子系统规范。

  • 最大化窗口 --- 将窗口的大小增加到允许的最大尺寸,可以是垂直方向、水平方向或两个方向都增加。

    WindowListener 接口定义了处理大多数窗口事件的方法,例如打开和关闭窗口的事件,窗口的激活和非激活,以及窗口的图标化和取消图标化。

    另外两个窗口监听器接口是 WindowFocusListenerWindowStateListenerWindowFocusListener 包含用于检测窗口何时成为焦点所有者或失去焦点所有者状态的方法。WindowStateListener 有一个方法用于检测窗口状态的更改,例如窗口被图标化、取消图标化、最大化或恢复为正常状态。

    虽然您可以使用 WindowListener 方法来检测一些窗口状态,例如图标化,但有两个原因使 WindowStateListener 更可取:它只有一个需要您实现的方法,并且它支持最大化。


    注意: 并非所有窗口管理器/本地平台都支持所有窗口状态。java.awt.Toolkit 方法 isFrameStateSupported(int) 可用于确定特定窗口状态是否受特定窗口管理器支持。稍后在本节中描述的 WindowEventDemo 示例展示了如何使用此方法。


    窗口监听器通常用于实现自定义窗口关闭行为。例如,窗口监听器用于在关闭窗口之前保存数据,或者在最后一个窗口关闭时退出程序。

    用户不一定需要实现窗口监听器来指定用户关闭窗口时窗口应该执行的操作。默认情况下,当用户关闭窗口时,窗口变为不可见。要指定不同的行为,请使用JFrameJDialog类的setDefaultCloseOperation方法。要实现窗口关闭处理程序,请使用setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE)方法,以便使窗口监听器提供所有窗口关闭职责。有关如何使用setDefaultCloseOperation的详细信息,请参见响应窗口关闭事件。

    当 Java 虚拟机(VM)中的最后一个可显示窗口被销毁时,VM 可能会终止。但请注意,在程序自动退出之前可能会有延迟,并且在某些情况下程序可能会继续运行。使用System.exit(int)显式退出程序更快更安全。有关更多信息,请参见AWT 线程问题

    窗口监听器通常也用于在窗口最小化时停止线程并释放资源,并在窗口恢复正常时重新启动。这样可以避免不必要地使用处理器或其他资源。例如,当包含动画的窗口被最小化时,应该停止其动画线程并释放任何大型缓冲区。当窗口恢复正常时,可以重新启动线程并重新创建缓冲区。

    以下示例演示了窗口事件。一个不可编辑的文本区域报告了由其窗口触发的所有窗口事件。此演示实现了WindowListenerWindowFocusListenerWindowStateListener接口中的所有方法。您可以在WindowEventDemo.java中找到演示的代码。


    试试这个:

    1. 单击"启动"按钮以使用Java™ Web Start运行 WindowEventDemo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。

    2. 当窗口出现时,已经显示了几条消息。一行报告您的窗口管理器是否支持 MAXIMIZED_BOTH。如果窗口管理器不支持其他窗口状态,也会报告此条件。接下来,会显示几行,报告窗口的窗口监听器已接收到窗口打开、激活和获得焦点事件。窗口中显示的所有消息也会发送到标准输出。

    3. 单击另一个窗口。将显示"窗口失去焦点"和"窗口失活"消息。如果此窗口不是框架或对话框,则会接收激活或失活事件。

    4. 单击 WindowEventDemo 窗口。您将看到"窗口激活"和"窗口获得焦点"消息。

    5. 使用窗口控件将窗口图标化。将显示两条图标化消息,一条来自窗口监听器,另一条来自窗口状态监听器。除非您查看标准输出,否则这些消息将在窗口取消图标化之前不会显示。还会报告窗口失活和窗口失去焦点事件。

    6. 取消图标化窗口。窗口监听器和窗口状态监听器都会显示两条取消图标化消息。WindowStateListener类中的windowStateChanged方法提供了与WindowListener类中的windowIconifiedwindowDeiconified方法相同的信息。还会报告窗口激活和窗口获得焦点事件。

    7. 最大化窗口,如果你的外观提供了这样的功能。请注意,一些外观在一些窗口管理器上运行,比如在 dtwm 上的 Java 外观,提供了最大化窗口的方法,但不会报告任何事件。这是因为 dtwm 通过调整窗口大小来模拟最大化,但这不是真正的最大化事件。一些外观只提供在垂直或水平方向上最大化窗口的方法。尝试使用窗口控件来查看有哪些选项可用。

    8. 使用窗口控件关闭窗口。将显示一个窗口关闭消息。一旦窗口关闭,将向标准输出发送一个窗口关闭消息。


    这是演示窗口事件处理代码:

    java 复制代码
    public class WindowEventDemo extends JFrame implements WindowListener,
                                                WindowFocusListener,
                                                WindowStateListener {
        ...
        static WindowEventDemo frame = new WindowEventDemo("WindowEventDemo");
        JTextArea display;
        ...
    
        private void addComponentsToPane() {
            display = new JTextArea();
            display.setEditable(false);
            JScrollPane scrollPane = new JScrollPane(display);
            scrollPane.setPreferredSize(new Dimension(500, 450));
            getContentPane().add(scrollPane, BorderLayout.CENTER);
    
            addWindowListener(this);
            addWindowFocusListener(this);
            addWindowStateListener(this);
    
            checkWM();
        }
    
        public WindowEventDemo(String name) {
            super(name);
        }
    
        //Some window managers don't support all window states.
    
        public void checkWM() {
            Toolkit tk = frame.getToolkit();
            if (!(tk.isFrameStateSupported(Frame.ICONIFIED))) {
                displayMessage(
                        "Your window manager doesn't support ICONIFIED.");
            }  else displayMessage(
                    "Your window manager supports ICONIFIED.");
            if (!(tk.isFrameStateSupported(Frame.MAXIMIZED_VERT))) {
                displayMessage(
                        "Your window manager doesn't support MAXIMIZED_VERT.");
            }  else displayMessage(
                    "Your window manager supports MAXIMIZED_VERT.");
            if (!(tk.isFrameStateSupported(Frame.MAXIMIZED_HORIZ))) {
                displayMessage(
                        "Your window manager doesn't support MAXIMIZED_HORIZ.");
            } else displayMessage(
                    "Your window manager supports MAXIMIZED_HORIZ.");
            if (!(tk.isFrameStateSupported(Frame.MAXIMIZED_BOTH))) {
                displayMessage(
                        "Your window manager doesn't support MAXIMIZED_BOTH.");
            } else {
                displayMessage(
                        "Your window manager supports MAXIMIZED_BOTH.");
            }
        }
    
        public void windowClosing(WindowEvent e) {
            displayMessage("WindowListener method called: windowClosing.");
            //A pause so user can see the message before
            //the window actually closes.
            ActionListener task = new ActionListener() {
                boolean alreadyDisposed = false;
                public void actionPerformed(ActionEvent e) {
                    if (frame.isDisplayable()) {
                        alreadyDisposed = true;
                        frame.dispose();
                    }
                }
            };
            Timer timer = new Timer(500, task); //fire every half second
            timer.setInitialDelay(2000);        //first delay 2 seconds
            timer.setRepeats(false);
            timer.start();
        }
    
        public void windowClosed(WindowEvent e) {
            //This will only be seen on standard output.
            displayMessage("WindowListener method called: windowClosed.");
        }
    
        public void windowOpened(WindowEvent e) {
            displayMessage("WindowListener method called: windowOpened.");
        }
    
        public void windowIconified(WindowEvent e) {
            displayMessage("WindowListener method called: windowIconified.");
        }
    
        public void windowDeiconified(WindowEvent e) {
            displayMessage("WindowListener method called: windowDeiconified.");
        }
    
        public void windowActivated(WindowEvent e) {
            displayMessage("WindowListener method called: windowActivated.");
        }
    
        public void windowDeactivated(WindowEvent e) {
            displayMessage("WindowListener method called: windowDeactivated.");
        }
    
        public void windowGainedFocus(WindowEvent e) {
            displayMessage("WindowFocusListener method called: windowGainedFocus.");
        }
    
        public void windowLostFocus(WindowEvent e) {
            displayMessage("WindowFocusListener method called: windowLostFocus.");
        }
    
        public void windowStateChanged(WindowEvent e) {
            displayStateMessage(
              "WindowStateListener method called: windowStateChanged.", e);
        }
    
        void displayMessage(String msg) {
            display.append(msg + newline);
            System.out.println(msg);
        }
    
        void displayStateMessage(String prefix, WindowEvent e) {
            int state = e.getNewState();
            int oldState = e.getOldState();
            String msg = prefix
                       + newline + space
                       + "New state: "
                       + convertStateToString(state)
                       + newline + space
                       + "Old state: "
                       + convertStateToString(oldState);
            displayMessage(msg);
        }
    
        String convertStateToString(int state) {
            if (state == Frame.NORMAL) {
                return "NORMAL";
            }
            String strState = " ";
            if ((state & Frame.ICONIFIED) != 0) {
                strState += "ICONIFIED";
            }
            //MAXIMIZED_BOTH is a concatenation of two bits, so
            //we need to test for an exact match.
            if ((state & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_BOTH) {
                strState += "MAXIMIZED_BOTH";
            } else {
                if ((state & Frame.MAXIMIZED_VERT) != 0) {
                    strState += "MAXIMIZED_VERT";
                }
                if ((state & Frame.MAXIMIZED_HORIZ) != 0) {
                    strState += "MAXIMIZED_HORIZ";
                }
                if (" ".equals(strState)){
                    strState = "UNKNOWN";
                }
            }
            return strState.trim();
        }
    }

    窗口监听器 API

    窗口监听器 API 由三个窗口监听器接口和WindowEvent类组成。它们的方法列在以下表中:

    • WindowListener 接口

    • WindowFocusListener 接口

    • WindowStateListener 接口

    • WindowEvent 类所有三个接口的方法都可以通过WindowAdapter类来使用。

    WindowListener 接口

    方法 目的
    windowOpened(WindowEvent) 在所监听窗口首次显示后立即调用。
    windowClosing(WindowEvent) 响应用户请求关闭所监听窗口时调用。要实际关闭窗口,监听器应调用窗口的disposesetVisible(false)方法。
    windowClosed(WindowEvent) 在所监听窗口关闭后立即调用。
    windowIconified(WindowEvent) windowDeiconified(WindowEvent) 在所监听窗口最小化或取消最小化后立即调用。
    windowActivated(WindowEvent) windowDeactivated(WindowEvent) 在所监听窗口激活或停用后立即调用。这些方法不会发送给非框架或对话框的窗口。因此,更倾向于使用windowGainedFocuswindowLostFocus方法来确定窗口何时获得或失去焦点。

    窗口焦点监听器接口

    Method Purpose
    windowGainedFocus(WindowEvent) windowLostFocus(WindowEvent) 在所监听窗口获得或失去焦点后立即调用。

    窗口状态监听器接口

    Method Purpose

    | windowStateChanged(WindowEvent) | 在所监听窗口的状态通过最小化、最大化或恢复正常而改变后立即调用。状态通过WindowEvent以位掩码的形式可用。可能的值在java.awt.Frame中定义为:

    • NORMAL. 表示没有设置任何状态位。

    • ICONIFIED.

    • MAXIMIZED_HORIZ.

    • MAXIMIZED_VERT.

    • MAXIMIZED_BOTH. 连接MAXIMIZED_HORIZMAXIMIZED_VERT。窗口管理器可能支持MAXIMIZED_BOTH,而不支持MAXIMIZED_HORIZMAXIMIZED_VERTjava.awt.Toolkit方法isFrameStateSupported(int)可用于确定窗口管理器支持哪些状态。

    |

    WindowEvent 类

    方法 目的
    Window getWindow() 返回触发事件的窗口。您可以使用这个方法代替getSource方法。
    Window getOppositeWindow() 返回与此焦点或激活更改相关的另一个窗口。对于WINDOW_ACTIVATEDWINDOW_GAINED_FOCUS事件,返回失去激活或焦点的窗口。对于WINDOW_DEACTIVATEDWINDOW_LOST_FOCUS事件,返回获得激活或焦点的窗口。对于具有不同 VM 或上下文中的 Java 应用程序的任何其他类型的WindowEvent,或者没有其他窗口的情况,返回null
    int getOldState() int getNewState() 对于WINDOW_STATE_CHANGED事件,这些方法返回窗口的先前状态或新状态作为位掩码。

    使用窗口监听器的示例

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

    示例 描述位置 注释
    WindowEventDemo 本节 报告在一个窗口上发生的所有窗口事件,以展示触发窗口事件的情况。
    SliderDemo 如何使用滑块 监听窗口最小化和还原事件,以便在窗口不可见时停止动画。
    InternalFrameEventDemo 如何编写内部框架监听器 报告在一个内部框架上发生的所有内部框架事件,以展示触发内部框架事件的情况。内部框架事件类似于窗口事件。
    DialogDemo 文本组件特性 CustomDialog.java 使用setDefaultCloseOperation而不是窗口监听器来确定用户关闭窗口时要采取的操作。
    框架 --- 一个允许创建和销毁多个窗口的演示。
相关推荐
是小崔啊33 分钟前
开源轮子 - EasyExcel02(深入实践)
java·开源·excel
mazo_command1 小时前
【MATLAB课设五子棋教程】(附源码)
开发语言·matlab
myNameGL1 小时前
linux安装idea
java·ide·intellij-idea
IT猿手1 小时前
多目标应用(一):多目标麋鹿优化算法(MOEHO)求解10个工程应用,提供完整MATLAB代码
开发语言·人工智能·算法·机器学习·matlab
青春男大1 小时前
java栈--数据结构
java·开发语言·数据结构·学习·eclipse
88号技师1 小时前
几款性能优秀的差分进化算法DE(SaDE、JADE,SHADE,LSHADE、LSHADE_SPACMA、LSHADE_EpSin)-附Matlab免费代码
开发语言·人工智能·算法·matlab·优化算法
Zer0_on1 小时前
数据结构栈和队列
c语言·开发语言·数据结构
一只小bit1 小时前
数据结构之栈,队列,树
c语言·开发语言·数据结构·c++
HaiFan.2 小时前
SpringBoot 事务
java·数据库·spring boot·sql·mysql
我要学编程(ಥ_ಥ)2 小时前
一文详解“二叉树中的深搜“在算法中的应用
java·数据结构·算法·leetcode·深度优先