java detect when any window is created or closed
Asked Answered
F

2

7

Is it possible to be notified whenever any window in the application was created or closed?

At the moment I'm polling Window.getWindows() but I would prefer to get notified instead.

What I have:

List<Window> previousWindows = new ArrayList<>();
while (true) {
    List<Window> currentWindows = Arrays.asList(Window.getWindows());

    for (Window window : currentWindows) {
        if (!previousWindows.contains(window)) {
            //window was created
        }
    }

    for (Window window : previousWindows) {
        if (!currentWindows.contains(window)) {
            //window was closed
        }
    }

    previousWindows = currentWindows;
    Thread.sleep(1000);
}

What I'd like:

jvm.addWindowListener(this);

@Override
public void windowWasDisplayed(Window w) {
    //window was created
}

@Override
public void windowWasClosed(Window w) {
    //window was closed
}
Funchal answered 23/12, 2015 at 17:55 Comment(9)
Are you using AWT Window or Swing JFrame? If you're using Swing, don't tag AWT, or viceversa. Or are you using both?Candelabrum
It appears to be a bit of both. When I call Window.getWindows(), it's an array of awt windows. But I am using JFrames throughout the application.Funchal
For Swing and know when a window is opened: See How do i find if a window is opened on swing and Hande JFrame Window Events and for AWT see WindowListener#windowOpened from docsCandelabrum
Also, for better help sooner, please post an MCVE which you should have done atm of asking this question :)Candelabrum
Thanks Frak, but those solutions require me modify all the places that a JFrame is created. Is it possible to have an application-wide hook instead? Ie. Is there a way to ask the JVM to inform me whenever a window is created or closed?Funchal
I'd recommend you not to use multiple JFrames, read The use of multiple JFrames, Good/Bad Practice maybe use CardLayout or modal JDialogs avoid the use of AWT whenever possible, it's deprecated, Swing was made to correct many problems AWT had.Candelabrum
Note that JFrames are AWT Windows, as are the other top-level Swing containers, JWindow and JDialog.Greyback
Thanks Frak, I've updated the question to have a MCVE. We have multiple windows being created (one for each screen of a multi-screen computer).Funchal
Thanks John, yes happy to get notified of any of those tooFunchal
G
11

You can register listeners that receive any subset of types of AWT events via the windowing Toolkit. From those you can select and handle the WindowEvents for windows being opened and closed, something like this:

class WindowMonitor implements AWTEventListener {
    public void eventDispatched(AWTEvent event) {
        switch (event.getID()){
            case WindowEvent.WINDOW_OPENED:
                doSomething();
                break;
            case WindowEvent.WINDOW_CLOSED:
                doSomethingElse();
                break;
        }
    }

    // ...
}

class MyClass {

    // alternative 1
    public void registerListener() {
        Toolkit.getDefaultToolkit().addAWTEventListener(new WindowMonitor(),
                AWTEvent.WINDOW_EVENT_MASK);
    }

    // alternative 2
    public void registerListener(Component component) {
        component.getToolkit().addAWTEventListener(new WindowMonitor(),
                AWTEvent.WINDOW_EVENT_MASK);
    }
}

I would recommend alternative 2, where the Component from which you obtain the Toolkit is the main frame of your application (there should be only one), but alternative 1 should work out for you if you have to do this without reference to any particular component (for instance, before any have been created).

Do note, however, that registering an AWTEventListener is subject to a security check.

Greyback answered 23/12, 2015 at 18:39 Comment(1)
Superb answer! Thank you John. Exactly what I was looking forFunchal
L
0

If you create the additional windows (I assume JFrames) yourself, you can use the addWindowListener method. The WindowAdapter abstract class allows you to override methods for the events you are interested in:

import java.awt.event.*;
import javax.swing.*;

public class MultipleWindows {
    public static void main(String[] arguments) {
        SwingUtilities.invokeLater(() -> new MultipleWindows().createAndShowGui());
    }

    private void createAndShowGui() {
        JFrame frame = new JFrame("Stack Overflow");
        frame.setBounds(100, 100, 800, 600);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        JPanel panel = new JPanel();
        panel.add(new JLabel("Testing multiple windows..."));
        frame.getContentPane().add(panel);

        WindowAdapter windowAdapter = new WindowAdapter() {
            @Override
            public void windowOpened(WindowEvent windowEvent) {
                System.out.println("Window opened: "
                                   + windowEvent.getWindow().getName());
            }

            @Override
            public void windowClosed(WindowEvent windowEvent) {
                System.out.println("Window closed: "
                                   + windowEvent.getWindow().getName());
            }
        };

        for (int windowIndex = 2; windowIndex < 6; windowIndex++) {
            String title = "Window " + windowIndex;
            JFrame extraFrame = new JFrame(title);
            extraFrame.setName(title);
            extraFrame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
            extraFrame.addWindowListener(windowAdapter);
            extraFrame.setVisible(true);
        }

        frame.setVisible(true);
    }
}
Lilienthal answered 23/12, 2015 at 18:41 Comment(3)
I'm pretty sure that registering a WindowListener on a Window only causes the listener to receive WindowEvents fired by that Window, not any fired by any other Windows.Greyback
@JohnBollinger - yes, you are completely right. This approach is targeted at the use case where you are interested in events for the windows that you create directly. If required, you could call the Window.getWindows method to register window listeners for other windows as well.Lilienthal
@Freek de Bruijn please to see my answer here, is only for you, be sure WindowListener is correct wayStaphylococcus

© 2022 - 2024 — McMap. All rights reserved.