杰瑞科技汇

Java WindowListener如何实现窗口事件监听?

Of course! Let's dive deep into the WindowListener interface in Java. This is a fundamental part of building graphical user interfaces (GUIs) using the Swing or AWT libraries.

Java WindowListener如何实现窗口事件监听?-图1
(图片来源网络,侵删)

What is a WindowListener?

A WindowListener is an interface in the java.awt.event package that allows you to listen for events related to a Window object. In Swing, this includes JFrame, JDialog, and JWindow.

Think of it as a security guard for your window. This "guard" watches for specific actions and can react to them. The actions (events) it listens for are:

  1. Opening (windowOpened)
  2. Closing (windowClosing)
  3. Closed (windowClosed)
  4. Iconified (minimized, windowIconified)
  5. De-iconified (restored from being minimized, windowDeiconified)
  6. Activated (gains focus, windowActivated)
  7. Deactivated (loses focus, windowDeactivated)

The Interface and its Methods

The WindowListener interface has seven methods, one for each event:

public interface WindowListener extends EventListener {
    // Called after the window has been opened.
    void windowOpened(WindowEvent e);
    // Called when the user attempts to close the window (e.g., clicks the 'X').
    void windowClosing(WindowEvent e);
    // Called after the window has been closed.
    void windowClosed(WindowEvent e);
    // Called when the window is changed to an icon (minimized).
    void windowIconified(WindowEvent e);
    // Called when the window is restored from an icon.
    void windowDeiconified(WindowEvent e);
    // Called when the window is set to be the active window.
    void windowActivated(WindowEvent e);
    // Called when the window is no longer the active window.
    void windowDeactivated(WindowEvent e);
}

Key Distinction: windowClosing vs. windowClosed This is a very common point of confusion and is crucial to understand:

Java WindowListener如何实现窗口事件监听?-图2
(图片来源网络,侵删)
  • windowClosing: This event is fired when the user tries to close the window. At this point, the window is still visible. You can use this event to ask the user "Are you sure you want to exit?" before actually closing the application.
  • windowClosed: This event is fired after the window has been successfully closed and removed from the screen. You cannot interact with the window at this point.

How to Use a WindowListener

There are three main ways to use a WindowListener:

  1. Implementing the Interface (The "Classic" Way)
  2. Using an Anonymous Inner Class (The Common Way)
  3. Using a Lambda Expression (The Modern, Java 8+ Way)

Let's look at examples for each.

Setup: A Simple JFrame

First, let's create a basic JFrame that we will add our listeners to.

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
public class MyWindow {
    public static void main(String[] args) {
        // Ensure the GUI is created on the Event Dispatch Thread (EDT)
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("WindowListener Demo");
            frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); // See explanation below
            frame.setSize(400, 300);
            frame.setLocationRelativeTo(null); // Center the window
            frame.add(new JLabel("Try closing, minimizing, and focusing this window."));
            // We will add the listener here in the examples below
            // addWindowListener(frame);
            frame.setVisible(true);
        });
    }
}

Note: We set setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE). This is important because if we use JFrame.EXIT_ON_CLOSE, the program will exit immediately when the 'X' is clicked, and our windowClosing listener will never have a chance to run. We will handle the closing logic manually in our listener.

Java WindowListener如何实现窗口事件监听?-图3
(图片来源网络,侵删)

Method 1: Implementing the Interface

This approach involves creating a separate class that implements WindowListener and then creating an instance of that class to add to the frame.

Pros:

  • Keeps the listener logic separate and reusable.
  • Good for complex listeners.

Cons:

  • Can be verbose (boilerplate code).
// 1. Create a class that implements the interface
class MyWindowListener implements WindowListener {
    @Override
    public void windowOpened(WindowEvent e) {
        System.out.println("Window opened.");
    }
    @Override
    public void windowClosing(WindowEvent e) {
        System.out.println("Window is closing...");
        // Ask for confirmation before exiting
        int option = javax.swing.JOptionPane.showConfirmDialog(
            null,
            "Are you sure you want to exit?",
            "Confirm Exit",
            javax.swing.JOptionPane.YES_NO_OPTION
        );
        if (option == javax.swing.JOptionPane.YES_OPTION) {
            // Dispose the window to close it
            e.getWindow().dispose();
        }
    }
    @Override
    public void windowClosed(WindowEvent e) {
        System.out.println("Window closed.");
        // If this is the main window, you might want to exit the application
        System.exit(0);
    }
    @Override
    public void windowIconified(WindowEvent e) {
        System.out.println("Window minimized.");
    }
    @Override
    public void windowDeiconified(WindowEvent e) {
        System.out.println("Window restored.");
    }
    @Override
    public void windowActivated(WindowEvent e) {
        System.out.println("Window activated.");
    }
    @Override
    public void windowDeactivated(WindowEvent e) {
        System.out.println("Window deactivated.");
    }
}
// In your main class, you would use it like this:
// MyWindowListener listener = new MyWindowListener();
// frame.addWindowListener(listener);

Method 2: Using an Anonymous Inner Class

This is the most common pre-Java 8 way to handle listeners. It allows you to implement the interface and create an instance in one go, keeping the code localized.

// In your main method, after creating the frame:
frame.addWindowListener(new WindowListener() {
    @Override
    public void windowOpened(WindowEvent e) {
        System.out.println("Window opened.");
    }
    @Override
    public void windowClosing(WindowEvent e) {
        System.out.println("Window is closing...");
        int option = javax.swing.JOptionPane.showConfirmDialog(
            null,
            "Are you sure you want to exit?",
            "Confirm Exit",
            javax.swing.JOptionPane.YES_NO_OPTION
        );
        if (option == javax.swing.JOptionPane.YES_OPTION) {
            e.getWindow().dispose();
        }
    }
    @Override
    public void windowClosed(WindowEvent e) {
        System.out.println("Window closed.");
        System.exit(0);
    }
    @Override
    public void windowIconified(WindowEvent e) {
        System.out.println("Window minimized.");
    }
    @Override
    public void windowDeiconified(WindowEvent e) {
        System.out.println("Window restored.");
    }
    @Override
    public void windowActivated(WindowEvent e) {
        System.out.println("Window activated.");
    }
    @Override
    public void windowDeactivated(WindowEvent e) {
        System.out.println("Window deactivated.");
    }
});

Method 3: Using a Lambda Expression (Java 8+)

This is the modern, most concise, and often preferred way. Since most of the methods in WindowListener are only used once, lambdas are a perfect fit. You can use the WindowAdapter (see next section) for an even cleaner approach, but you can also implement the full interface.

// In your main method, after creating the frame:
frame.addWindowListener(new WindowListener() {
    @Override
    public void windowClosing(WindowEvent e) {
        // We only care about the closing event for this example
        System.out.println("Window is closing via Lambda...");
        int option = javax.swing.JOptionPane.showConfirmDialog(
            null,
            "Are you sure you want to exit?",
            "Confirm Exit",
            javax.swing.JOptionPane.YES_NO_OPTION
        );
        if (option == javax.swing.JOptionPane.YES_OPTION) {
            e.getWindow().dispose();
        }
    }
    // Provide empty implementations for the rest
    @Override public void windowOpened(WindowEvent e) {}
    @Override public void windowClosed(WindowEvent e) { System.exit(0); }
    @Override public void windowIconified(WindowEvent e) {}
    @Override public void windowDeiconified(WindowEvent e) {}
    @Override public void windowActivated(WindowEvent e) {}
    @Override public void windowDeactivated(WindowEvent e) {}
});

A Better Alternative: WindowAdapter

Implementing all seven methods is often tedious if you only care about one or two events. Java provides a convenience class called java.awt.event.WindowAdapter that provides default (empty) implementations for all WindowListener methods.

You can then extend this class and only override the methods you need.

Example using WindowAdapter with an Anonymous Inner Class:

This is cleaner than implementing the full interface.

// In your main method, after creating the frame:
frame.addWindowListener(new Window
分享:
扫描分享到社交APP
上一篇
下一篇