How to listen for close in a JPanel

2019-07-31 23:58发布

问题:

I am working with some strange legacy code. They have a custom object which implements a JPanel. This JPanel object is a secondary popup screen within the main application. The issue I'm having is to detect when the secondary popup screen is closed.

I tried to implement a WindowListener for the class, but when I try to add it, there is no JFrame associated with this object. I am assuming this is because they are using a custom object and it is an embedded popup screen.

I tried to retrieve a JFrame using:

JFrame parentFrame = (JFrame) SwingUtilities.getWindowAncestor(this);

which fails on a NullPointerException. I have no idea why it's so difficult to detect the right hand corner "x" close button on this page! I should mention that they were able to add Mouse and Key Listeners to the table which is embedded within the JPanel. But the outside listener for the entire window is causing me troubles.

(Please bear with me, this is my first stackoverflow post and I am new to Swing.)

Thanks so very much!!

回答1:

Try to call getParent() for that strange panel. It should return the parent GUI component. If this is still not your frame but some intermediate panel instead, call getParent() on it as well. The top level component returns null.

   Component p = strangePanel;
   while ( p != null && ! (p instanceof Window))
     p = p.getParent();

   ((Window) p ).addWindowListener(..);


回答2:

Cannot understand why you are getting "NullPointerException" at:

JFrame parentFrame = (JFrame) SwingUtilities.getWindowAncestor(this);

In two cases this can happen:

JFrame parentFrame = (JFrame) SwingUtilities.getWindowAncestor(null);

In your case, this is not possible as you have used this as a parameter.

Second, are you doing some other operations in above code line, like:

JFrame parentFrame = ((JFrame) SwingUtilities.getWindowAncestor(this)).someOperation();

In this case, if your this object represent the top window then you are supposed to get "NullPointerException" because ancestor of top parent is returned as "null". In other cases, I suspect you will get this exception.

Can you post a block of code where you are getting exception.



回答3:

For this answer I'm making a minor assumption that the Nullpointer is not being thrown at the line that you mentioned, but rather when you attempt to add the WindowListener to the parentFrame. This is most likely because you're calling

JFrame parentFrame = (JFrame) SwingUtilities.getWindowAncestor(this);

before the JPanel has been added to the JFrame hierarchy.

Here's a rought code sample on how you could work around this. The thought it to wait for the panel to be notified that it has been attached to the JFrame somewhere in its hierarchy.

package test;

import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class HierarchyTest extends JPanel {

    protected static void loadApp() {
        HierarchyTest test = new HierarchyTest();
        JFrame frame = new JFrame();
        frame.add(test);
        frame.setSize(200, 200);
        frame.setVisible(true);
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                loadApp();

            }
        });

    }

    public HierarchyTest() {
        this.addHierarchyListener(new HierarchyListener() {

            @Override
            public void hierarchyChanged(HierarchyEvent e) {
                // This can be optimized by checking the right flags, but I leave that up to you to look into
                boolean connected = setupListenersWhenConnected();

                if (connected) {
                    HierarchyTest.this.removeHierarchyListener(this);
                }
            }
        });
    }

    protected boolean setupListenersWhenConnected() {
        JFrame parentFrame = (JFrame) SwingUtilities.getWindowAncestor(this);
        if (parentFrame == null) {
            return false;
        }
        parentFrame.addWindowListener(new WindowAdapter() {

            @Override
            public void windowClosing(WindowEvent e) {
                // Implementation here
                System.out.println("This window is closing!");
            }
        });
        return true;
    }
}