5

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
}
Fidel
  • 7,027
  • 11
  • 57
  • 81
  • Are you using AWT Window or Swing JFrame? If you're using Swing, don't tag AWT, or viceversa. Or are you using both? – Frakcool Dec 23 '15 at 18:00
  • 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. – Fidel Dec 23 '15 at 18:03
  • For Swing and know when a window is opened: See [How do i find if a window is opened on swing](http://stackoverflow.com/questions/5890649/how-do-i-find-if-a-window-is-opened-on-swing) and [Hande JFrame Window Events](http://www.java2s.com/Code/Java/Swing-JFC/HandleJFramewindowevents.htm) and for AWT see [WindowListener#windowOpened](https://docs.oracle.com/javase/7/docs/api/java/awt/event/WindowListener.html#windowOpened(java.awt.event.WindowEvent)) from docs – Frakcool Dec 23 '15 at 18:03
  • 1
    Also, for better help sooner, please post an [MCVE](http://stackoverflow.com/help/mcve) which you should have done atm of asking this question :) – Frakcool Dec 23 '15 at 18:06
  • 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? – Fidel Dec 23 '15 at 18:06
  • 1
    I'd recommend you not to use multiple JFrames, read [The use of multiple JFrames, Good/Bad Practice](http://stackoverflow.com/questions/9554636/the-use-of-multiple-jframes-good-bad-practice) maybe use [CardLayout](https://docs.oracle.com/javase/tutorial/uiswing/layout/card.html) or modal [JDialogs](https://docs.oracle.com/javase/7/docs/api/javax/swing/JDialog.html) avoid the use of AWT whenever possible, it's deprecated, Swing was made to correct many problems AWT had. – Frakcool Dec 23 '15 at 18:13
  • Note that `JFrame`s *are* AWT `Windows`, as are the other top-level Swing containers, `JWindow` and `JDialog`. – John Bollinger Dec 23 '15 at 18:17
  • 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). – Fidel Dec 23 '15 at 18:19
  • Thanks John, yes happy to get notified of any of those too – Fidel Dec 23 '15 at 18:19

2 Answers2

10

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.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
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);
    }
}
Freek de Bruijn
  • 3,552
  • 2
  • 22
  • 28
  • 1
    I'm pretty sure that registering a `WindowListener` on a `Window` only causes the listener to receive `WindowEvent`s fired by that `Window`, not any fired by any other `Window`s. – John Bollinger Dec 23 '15 at 18:44
  • 1
    @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. – Freek de Bruijn Dec 23 '15 at 18:52
  • @Freek de Bruijn please to see my answer here, is only for you, be sure WindowListener is correct way – mKorbel Dec 23 '15 at 19:34