34

Is there a way to close a JDialog through code such that the Window event listeners will still be notified? I've tried just setting visible to false and disposing, but neither seem to do it.

Daniel Kaplan
  • 62,768
  • 50
  • 234
  • 356
Jeff Storey
  • 56,312
  • 72
  • 233
  • 406

5 Answers5

49

Closing a window (with dispose()) and hiding it (with setVisible(false)) are different operations, and produce different events -- and closing it from the operating system is yet another different operation that produces yet a different event.

All three will produce windowDeactivated to tell you the window's lost focus, but dispose() will then produce windowClosed, while closing from the OS will first produce windowClosing. If you want to handle both of these the same way, you can set the window to be disposed when closed:

window.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);

In general, setVisible(false) implies that you might want to use the window again, so it doesn't post any window events (apart from windowDeactivated). If you want to detect the hiding of a window, you need to use a ComponentListener;

window.addComponentListener(new ComponentAdapter() {
  @Override
  public void componentHidden(ComponentEvent e) {
    System.out.println("componentHidden()");
  }
})

Note though that this will pretty much only work for explicit setVisible() calls. If you need to detect hiding more generally, you can use a HierarchyListener, but it's probably more trouble than it's worth.

  window.addHierarchyListener(new HierarchyListener() {
    @Override
      public void hierarchyChanged(HierarchyEvent e) {
        System.out.println("valid: " + window.isValid());
        System.out.println("showing: " + window.isShowing());
      }
  });

Note that when you dispose a window you'll get a couple of HierarchyEvents, first for hiding and then for invalidation, but when you hide it with setVisible() it's still valid, so you won't get the invalidation.

murrayc
  • 2,103
  • 4
  • 17
  • 32
David Moles
  • 48,006
  • 27
  • 136
  • 235
  • 3
    Thanks David. I was only listening for windowClosing when using dispose. I didn't realize the only the OS closing it produced window closing. – Jeff Storey Aug 31 '09 at 14:19
  • I had to find out the hard way myself. :) – David Moles Aug 31 '09 at 15:28
  • Ok, I may still not understand the question. But the OP say he wants the "winder listeners to still be notified. My suggestion is to NOT use the dispose method, but to sent a windowClosing event tot the window. This will act just like somebody clicked on the "X" button. The window will be disposed and the window listener will be nofified. Its 2 lines of code. You seem to understand the problem better than I so maybe you will test my suggestion to see if it makes sense. – camickr Aug 31 '09 at 16:08
  • 1
    My confusion was that I didn't need it on windowClosing, but rather windowClosed. I wasn't trying to intercept windowClosing events, so by putting it in windowClosed, I can get the event either when the dialog is disposed either by hiding it and calling dispose OR if the user clicks the X. – Jeff Storey Aug 31 '09 at 22:13
  • camickr, posting a `windowClosing` event gets you a `windowClosing` event and (assuming the default close operation isn't `EXIT_ON_CLOSE`) a `windowDeactivated` event -- as you say, just as if the user clicked the X. That doesn't seem obviously more useful than the events you get with `dispose()` -- if all you want to do is close the window and get some events. It does have the advantage that it matches the behavior of the X, so you can handle both the X and your programmatic closing in the same way, but you can also get that (reversed) with `DISPOSE_ON_CLOSE`. IMHO that's cleaner, but YMMV. – David Moles Sep 01 '09 at 07:09
  • TL;DR: use dispose() and listen for windowClosed() – teh_senaus May 23 '14 at 13:42
3

I don't seem to have your problem. When I use the code below windowDeactivated() is called for either setVisible( false ) or dispose() and windowClosed() is also called for dispose().

ClosingDialog.java:

public class ClosingDialog extends JDialog {
    public ClosingDialog(Frame owner, String title, boolean modal) {
        super(owner, title, modal);
        JPanel contentPanel = (JPanel) this.getContentPane();

        JButton setVisButton = new JButton("setVisible( false )");
        setVisButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                ClosingDialog.this.setVisible(false);
            }
        });

        JButton disposeButton = new JButton("dispose()");
        disposeButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                ClosingDialog.this.dispose();
            }
        });

        contentPanel.setLayout(new FlowLayout());

        contentPanel.add(setVisButton);
        contentPanel.add(disposeButton);

        this.addWindowListener(new WindowListener() {
            public void windowActivated(WindowEvent e) {
                System.out.println("windowActivated");
            }

            public void windowClosed(WindowEvent e) {
                System.out.println("windowClosed");
            }

            public void windowClosing(WindowEvent e) {
                System.out.println("windowClosing");
            }

            public void windowDeactivated(WindowEvent e) {
                System.out.println("windowDeactivated");
            }

            public void windowDeiconified(WindowEvent e) {
                System.out.println("windowDeiconified");
            }

            public void windowIconified(WindowEvent e) {
                System.out.println("windowIconified");
            }

            public void windowOpened(WindowEvent e) {
                System.out.println("windowOpened");
            }
        });

        this.setSize(300, 300);
    }
}
Joseph Gordon
  • 2,356
  • 2
  • 23
  • 27
  • 2
    All windowDeactivated means is that is has lost focus. You don't know for sure if the window is actually closing. Generally WindowListeners will listen for the window closing event so they can do some special processing on a close. – camickr Aug 27 '09 at 23:51
  • Yes, I tried with windowClosing and did not receive that event. – Jeff Storey Aug 28 '09 at 00:14
  • Which is why I gave my solution 5 hours ago. – camickr Aug 28 '09 at 02:14
  • 1
    Typo: The action for `disposeButton` should call `ClosingDialog.this.dispose()`, not `setVisible(false)` again. If you do that, you get a `windowDeactivated` followed by a `windowClosed` -- or I do, at any rate. The `windowClosing` event is generally for closing a window via an OS control (e.g. the windows red X). – David Moles Aug 31 '09 at 08:25
  • Thanks, David. Totally missed it! – Joseph Gordon Aug 31 '09 at 13:40
1

Dispatch a windowClosing event to the Window. Check out the ExitAction example from the Closing an Application entry.

camickr
  • 321,443
  • 19
  • 166
  • 288
  • 3
    How do people learn anything if you don't give a reason for the down vote? – camickr Aug 27 '09 at 23:52
  • 3
    It wasn't me that downvoted it, but perhaps it's because it looks as though you didn't try to understand Jeff's problem, you just found linked to your most-likely-related existing blog post. The fact that you've posted two complaints about Jeff not liking your answer without any further attempt to find out why it's not working for him doesn't make the answer itself look any more attractive. – David Moles Aug 31 '09 at 08:21
  • I agree I could be out in left field but, my comment about one of us not understanding the other indicates I've looked at this several times trying to make sure I understand the question. My other comments are designed to have Jeff take another look at my suggestions. I still maintain I have a 1 line solution for his problem on creating images of a non displayed panel. – camickr Aug 31 '09 at 16:08
  • In my experience asking questions (or presenting alternative hypotheses) about the original question is more effective than just looking at it harder and/or suggesting the poster hasn't looked at your answer hard enough. You also seem to be fond of posting comments (like this one) complaining about the poster's failure to appreciate your answers to other questions, and I'm not sure who that's helping. But hey, your rep's 40% higher than mine with only 28% more answers, so clearly the downvotes can't be weighing you down too much. – David Moles Sep 01 '09 at 07:15
  • 2
    Its my experience that people like to be "spoon fed" the answer. So when presented the option of "posted code" versus "following a link and doing some reading" the former is usually choosen. So my comments are designed to nudge the poster into actually reading the link. By the way my suggestion results in both a windowClosing and WindowClosed event being generated when DISPOSE_ON_CLOSE is used. – camickr Sep 02 '09 at 15:27
0

Untested suggestion:

Have you tried getWindowListeners() and then iterating around to fire windowClosed() to each of the WindowListeners?

EDIT: the above suggestion is wrong. Keeping it for posterity.

I'm afraid calling dialog.dispose() works fine for me in my simple example.

Grundlefleck
  • 124,925
  • 25
  • 94
  • 111
0

I wanted to fire a windowClosing event from the code (just as if the user clicked the X), because I have an extra close button in the JDialog and want the same WindowListener (that I implemented using a WindowAdapter) to be run when the X is clicked and when the button is clicked. Running dispose() only fires windowClosed, not windowClosing, and I want a message to appear before the window is closed, for confirmation. I also didn't manage to fire windowClosing via JDialog's method processWindowEvent since it is protected.

Here is how I got it working though:

WindowAdapter adapter = (WindowAdapter)jdialog.getWindowListeners()[0];
adapter.windowClosing(new WindowEvent((Window)jdialog, WindowEvent.WINDOW_CLOSING));

Hope that helps someone.