1

Example below allows window to be showed, hided, disposed and closed (by sending event).

Example showed, that window is opened only once -- on first set visible. Even if a window is disposed, and then showed again, it doesn't undergo "open" event.

Why?

How to know if window is opened without writing a handler and tracking this event?

How to close window so that it undergo open event again on set visible? I.e. how to return window object back to initial state?

Is there any other state or event which can have the required properties?

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.AbstractAction;
import javax.swing.AbstractListModel;
import javax.swing.ComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.event.ListDataListener;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Tester_JFrame_Closing_01 {

    private static Logger log = LoggerFactory.getLogger(Tester_JFrame_Closing_01.class);

    protected static Toolkit toolkit = Toolkit.getDefaultToolkit();
    protected static EventQueue eventQueue = toolkit.getSystemEventQueue();

    public static enum CloseOperation {

        DO_NOTHING_ON_CLOSE(JFrame.DO_NOTHING_ON_CLOSE),
        HIDE_ON_CLOSE(JFrame.HIDE_ON_CLOSE),
        DISPOSE_ON_CLOSE(JFrame.DISPOSE_ON_CLOSE),
        EXIT_ON_CLOSE(JFrame.EXIT_ON_CLOSE)
        ;

        public static ComboBoxModel newModel() {

            return new ComboBoxModel() {
                private CloseOperation selected = HIDE_ON_CLOSE;

                @SuppressWarnings("serial")
                private final AbstractListModel core = new AbstractListModel() {

                    @Override
                    public int getSize() {
                        return values().length;
                    }

                    @Override
                    public Object getElementAt(int index) {
                        return values()[index];
                    }

                };

                @Override
                public int getSize() {
                    return core.getSize();
                }

                @Override
                public Object getElementAt(int index) {
                    return core.getElementAt(index);
                }

                @Override
                public void addListDataListener(ListDataListener l) {
                    core.addListDataListener(l);
                }

                @Override
                public void removeListDataListener(ListDataListener l) {
                    core.removeListDataListener(l);
                }

                @Override
                public void setSelectedItem(Object anItem) {
                    selected = (CloseOperation) anItem;
                }

                @Override
                public Object getSelectedItem() {
                    return selected;
                }

            };

        }


        public final int Value;

        private CloseOperation(int value) {
            this.Value = value;
        }

        @Override
        public String toString() {
            switch(this) {
            case DISPOSE_ON_CLOSE:
                return "DISPOSE_ON_CLOSE";
            case HIDE_ON_CLOSE:
                return "HIDE_ON_CLOSE";
            case DO_NOTHING_ON_CLOSE:
                return "DO_NOTHING_ON_CLOSE";
            case EXIT_ON_CLOSE:
                return "EXIT_ON_CLOSE";
            default:
                return "<UNKNOWN>";
            }
        }
    }

    public static void main(String[] args) {

        WindowAdapter windowAdapter = new WindowAdapter() {
            @Override
            public void windowClosed(WindowEvent e) {
                log.debug("windowClosed");
            }

            @Override
            public void windowClosing(WindowEvent e) {
                log.debug("windowClosing");
            }

            @Override
            public void windowOpened(WindowEvent e) {
                log.debug("windowOpened");
            }

        };

        final JFrame frame = new JFrame("Controlled window");
        frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
        frame.addWindowListener(windowAdapter);

        final WindowEvent closeEvent = new WindowEvent(frame, WindowEvent.WINDOW_CLOSING);

        @SuppressWarnings("serial")
        AbstractAction closeAction = new AbstractAction("close") {
            @Override
            public void actionPerformed(ActionEvent e) {
                eventQueue.postEvent(closeEvent);
            }
        };

        @SuppressWarnings("serial")
        AbstractAction hideAction = new AbstractAction("hide") {
            @Override
            public void actionPerformed(ActionEvent e) {
                frame.setVisible(false);
            }
        };

        @SuppressWarnings("serial")
        AbstractAction showAction = new AbstractAction("show") {
            @Override
            public void actionPerformed(ActionEvent e) {
                frame.setVisible(true);
            }
        };

        @SuppressWarnings("serial")
        AbstractAction disposeAction = new AbstractAction("dispose") {

            @Override
            public void actionPerformed(ActionEvent e) {
                frame.dispose();
            }
        };

        JButton closeButton = new JButton(closeAction);
        JButton hideButton = new JButton(hideAction);
        JButton showButton = new JButton(showAction);
        JButton disposeButton = new JButton(disposeAction);

        ComboBoxModel closeOperationModel = CloseOperation.newModel();

        final JComboBox closeOperationCombo = new JComboBox(closeOperationModel);
        closeOperationCombo.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                log.debug("closeOperationCombo.actionPerformed({})", e);
                frame.setDefaultCloseOperation(((CloseOperation)closeOperationCombo.getSelectedItem()).Value);
            }
        });

        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(new FlowLayout());

        buttonPanel.add(showButton);
        buttonPanel.add(hideButton);
        buttonPanel.add(disposeButton);
        buttonPanel.add(closeButton);
        buttonPanel.add(closeOperationCombo);

        JFrame controlFrame = new JFrame("Controller window");
        controlFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        controlFrame.setLayout(new FlowLayout());
        controlFrame.add(buttonPanel, BorderLayout.SOUTH);
        controlFrame.pack();
        controlFrame.setLocation(100, 100);
        controlFrame.setVisible(true);

        frame.setBounds(100, 100 + controlFrame.getHeight(), controlFrame.getWidth(), 480);

    }
}

INCREDIBLE

They have a field named Window.state which they even don't initialize (and hence it is zero), then they test it in show() method once and set it to 1 if it is 0. This is the only place state is used and here windowOpened is fired. No code to return state back to 0 anywhere. Moreover, they abandon this state variable in Frame subclass and override it with new one with the same name which hold some new states bitwise, including iconified and similar and forget about opened bit! Cool!

nobody
  • 19,814
  • 17
  • 56
  • 77
Suzan Cioc
  • 29,281
  • 63
  • 213
  • 385
  • `eventQueue.postEvent(closeEvent);` Why? – MadProgrammer Mar 06 '13 at 23:40
  • @MadProgrammer, instead of invoking `setVisible(false)` or `dispose()` directly, this is like a user clicking on the close button of the frame. Then the default close operation will be executed. – camickr Mar 07 '13 at 04:13
  • @camickr Okay, I'm still left scratching me head :P – MadProgrammer Mar 07 '13 at 04:45
  • 2
    @MadProgrammer, run the SSCCE after changing the `defaultCloseOperation()` to `DISPOSE_ON_CLOSE`. When you click on "Dispose" you get a "WindowClosed" message. When you click on "Close" you get "WindowClosing" and "WindowClosed". This allows you to potentially ask the user for confirmation when closing the frame. This is how my `ExitAction` works in [Closing an Application](http://tips4java.wordpress.com/2009/05/01/closing-an-application/). – camickr Mar 07 '13 at 05:16
  • @camickr I have no issue over the listener, that's fine. I'm confused over why they are trying to generate there own event. I guess they were trying to test the listener... – MadProgrammer Mar 07 '13 at 05:21
  • @MadProgrammer, yes, it was actually a good SSCCE (except for the use of the 3rd party API) because it showed the different ways they tried to solve the problem. – camickr Mar 07 '13 at 05:35

2 Answers2

2

how to return window object back to initial state?

If you want to return variables and components to initial state then I think you need to recreate the window.

How to close window so that it undergo open event again on set visible?

You can track the closing/opening of a window yourself by doing something like:

    WindowAdapter windowAdapter = new WindowAdapter()
    {
        boolean closed = false;

        @Override
        public void windowClosed(WindowEvent e) {
            closed = true;
            System.out.println("windowClosed");
        }

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

        @Override
        public void windowOpened(WindowEvent e) {
            System.out.println("windowOpened");
            closed = false;
        }

        @Override
        public void windowActivated(WindowEvent e) {
            System.out.println("windowActivated");

            if (closed)
                windowOpened(e);

        }
    };

In order for the "Close" button to work you would also need to use:

    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
camickr
  • 321,443
  • 19
  • 166
  • 288
  • You are using bad trick by handling `windowActivated` and calling `windowOpened` from within it. This doesnot mean subsytem would call it. The question is about subsystem: why does it call close multiple times and open only once? – Suzan Cioc Mar 07 '13 at 13:57
  • P.S. `setDefaultCloseOperation` method just defines what happen when user "closes" window by pressing cross button in window corner. – Suzan Cioc Mar 07 '13 at 14:17
  • That is the way it was designed and as I suggested I don't think there is anything you can do about it. Yes, setDefaultCloseOperation() applies when you click on the Close button of the window. If you leave it at "HIDE", then the windowClosed event will never be fired. I also believe that whether you click a "Close" menu item or a "Close" button the logic should be the same as if the user clicked the "Close" button on the window, that is why you should set the default close operation appropriately. See my `Closing an Application` link give in a comment to your question. – camickr Mar 07 '13 at 16:38
  • I found `state` bit inside `Window` class and I don't understand they don't set it back to zero on close or dispose. – Suzan Cioc Mar 07 '13 at 17:12
1

You can use this

To find the active Window(be it a frame or a dialog) in a java swing application you can use the following recursive method:

Window getSelectedWindow(Window[] windows) {
    Window result = null;
    for (int i = 0; i < windows.length; i++) {
        Window window = windows[i];
        if (window.isActive()) {
            result = window;
        } else {
            Window[] ownedWindows = window.getOwnedWindows();
            if (ownedWindows != null) {
                result = getSelectedWindow(ownedWindows);
            }
        }
    }
    return result;
}

Reference this article Get current active window's title in Java

Community
  • 1
  • 1
DotNetRussell
  • 9,716
  • 10
  • 56
  • 111