Window events are generated when the user performs certain actions on a Java frame:

  • Opening
  • Closing
  • Closed
  • Iconified (i.e. minimized)
  • Deiconified (i.e. restored)
  • Activated
  • Deactivated

All of these cause a WindowEvent to be generated by the frame, and if you wish to handle such events, you must specify a WindowListener for them.

Frame as Listener

Here’s a first cut at a class that listens to window events.  It uses the frame class itself as the listener:

package swingExamples;

import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;

import javax.swing.JFrame;

public class CloseableFrame1 extends JFrame
    implements WindowListener
{
  public CloseableFrame1()
  {
    setTitle("CloseableFrame1");
    addWindowListener(this);
  }
  
  // Methods required by WindowListener interface
  public void windowActivated(WindowEvent e)
  {
  }
  public void windowClosed(WindowEvent e)
  {
  }
  public void windowClosing(WindowEvent e)
  {
    System.exit(0); // Exit program
  }
  public void windowDeactivated(WindowEvent e)
  {
  }
  public void windowDeiconified(WindowEvent e)
  {
  }
  public void windowIconified(WindowEvent e)
  {
  }
  public void windowOpened(WindowEvent e)
  {
  }
  
  public static void main(String[] args)
  {
    CloseableFrame1 frame = new CloseableFrame1();
    frame.setSize(300, 200);
    frame.setVisible(true);
  }
}

which produces the following (again, fascinating) output:

Do you notice how many methods we had to implement that are empty — that is, they do nothing?

Separate Class as Listener

Here’s another example, where we’ve moved the responsibility for listening for windows events into a separate class:

package swingExamples;

import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;

import javax.swing.JFrame;

public class CloseableFrame2 extends JFrame
{
  public CloseableFrame2()
  {
    setTitle("CloseableFrame2");
    addWindowListener( new WindowCloser(this) );
  }
  
  public static void main(String[] args)
  {
    CloseableFrame2 frame = new CloseableFrame2();
    frame.setSize(300, 200);
    frame.setVisible(true);
  }
}

class WindowCloser implements WindowListener
{
  // Constructor
  WindowCloser(JFrame frame)
  {
    m_frame = frame;
  }
  
  // Methods required by WindowListener interface
  public void windowActivated(WindowEvent e)
  {
  }
  public void windowClosed(WindowEvent e)
  {
  }
  public void windowClosing(WindowEvent e)
  {
    m_frame.setVisible(false); // Make the frame invisible
    m_frame.dispose(); // Clean it up
    System.exit(0); // Exit program
  }
  public void windowDeactivated(WindowEvent e)
  {
  }
  public void windowDeiconified(WindowEvent e)
  {
  }
  public void windowIconified(WindowEvent e)
  {
  }
  public void windowOpened(WindowEvent e)
  {
  }
  
  //// Private data ////
  private JFrame m_frame;
}

which produces the dazzlingly interesting result:

Note that, in the above example, I’ve emphasized that you really should make the frame invisible, and then call dispose() on it, to clean it up.  

This isn’t so important if all you’re going to do is exit, but it is if you simply want to dismiss the frame and continue doing work.

Also, note that, in order to use these frame methods, I needed to save a reference to the frame, by passing it into the constructor.  

Does that technique sound familiar from somewhere?

Member Class as Listener

Yet another example.  Here, we move the separate class inside the frame class, and make it an inner class — specifically, a member class:

package swingExamples;

import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;

import javax.swing.JFrame;

public class CloseableFrame3 extends JFrame
{
  public CloseableFrame3()
  {
    setTitle("CloseableFrame3");
    addWindowListener(new WindowCloser());
  }
  
  public static void main(String[] args)
  {
    CloseableFrame3 frame = new CloseableFrame3();
    frame.setSize(300, 200);
    frame.setVisible(true);
  }
  
  //////// Inner class /////////
  
  class WindowCloser implements WindowListener
  {
    // No explicit constructor needed

    // Methods required by WindowListener interface
    public void windowActivated(WindowEvent e)
    {
    }
    public void windowClosed(WindowEvent e)
    {
    }
    public void windowClosing(WindowEvent e)
    {
      setVisible(false); // Make the frame invisible
      dispose(); // Clean it up
      System.exit(0); // Exit program
    }
    public void windowDeactivated(WindowEvent e)
    {
    }
    public void windowDeiconified(WindowEvent e)
    {
    }
    public void windowIconified(WindowEvent e)
    {
    }
    public void windowOpened(WindowEvent e)
    {
    }
  }
}

which produces the amazing result:

Notice how we no longer need to pass an explicit reference to the frame into the inner class’s constructor, because we have an implicit reference to the outer class automatically, as a result of it being a member class.

As a consequence, there are also fewer lines of code in this example, when compared with the previous example.

Anonymous Class as Listener

Here’s the equivalent program using an anonymous class as the windows event listener.  

This time, however, the anonymous class uses a WindowAdapter class to make the implementation even more succinct.  This has the great convenience of not forcing us to write a large number of empty, do-nothing methods in our listener class.

package swingExamples;

import java.awt.event.WindowEvent;
import java.awt.event.WindowAdapter;

import javax.swing.JFrame;

public class CloseableFrame4
    extends JFrame
{
  public CloseableFrame4()
  {
    setTitle("CloseableFrame4");
    addWindowListener(new WindowAdapter()
    {
      public void windowClosing(WindowEvent e)
      {
        setVisible(false);
        dispose();
        System.exit(0);
      }
    }
    );
  }
  
  public static void main(String[] args)
  {
    CloseableFrame4 frame = new CloseableFrame4();
    frame.setSize(300, 200);
    frame.setVisible(true);
  }
}

This time, we have the shortest version.

See how inner classes, and in particular, anonymous classes can really shorten your code, and once you understand them, also simplify your code, and make it more cohesive?