首页 > 解决方案 > 使用 addWindowListener 的困难

问题描述

我正在尝试实现一个侦听器来检测窗口的关闭。我的主类正在扩展其他类,因此我无法扩展不允许我使用 addWindowListener 的 JFrame。

我已经尝试了下面的代码,但它不起作用。

public class PowerPanel extends AnotherPanel  implements ActionListener, PropertyChangeListener {
    // logic …
        this.addWindowListener(new WindowAdapter() {
            public void windowClosing (WindowEvent e ) {
        // do things
    }
});
}

我得到的错误表明 addWindowListener 是“未定义类型 PowerPanel”。

标签: javaswingwindowlistener

解决方案


您不能将窗口侦听器添加到面板中 - 您需要将其添加到java.awt.Window实例中,在您的情况下是JFrame.

如果您很难将JFrame实例传递到面板中 - 您可以通过不同的方式访问它:

public class SamplePanel extends JPanel
{
    /**
     * Simple panel example that has no idea about it's parent window.
     */
    public SamplePanel ()
    {
        super ();

        // Your custom window listener
        final WindowAdapter windowAdapter = new WindowAdapter ()
        {
            @Override
            public void windowClosing ( final WindowEvent e )
            {
                System.out.println ( "Window is closing" );
            }
        };

        // Ancestor availability listener
        // It will make sure that whenever component appears on some visible window 
        // and is displayable container - we will add our window listener to it
        addAncestorListener ( new AncestorAdapter ()
        {
            /**
             * Saved window to remove listener from later on.
             */
            private Window window = null;

            @Override
            public void ancestorAdded ( final AncestorEvent event )
            {
                // Component appeared on some window, we can add our listener now
                addListener ();
            }

            @Override
            public void ancestorMoved ( final AncestorEvent event )
            {
                // Re-adding listener to potentially new parent window
                removeListener ();
                addListener ();
            }

            @Override
            public void ancestorRemoved ( final AncestorEvent event )
            {
                // Component was hidden or removed, we need to remove our listener
                removeListener ();
            }

            /**
             * Adds window listener.
             */
            protected void addListener ()
            {
                window = SwingUtilities.getWindowAncestor ( SamplePanel.this );
                if ( window != null )
                {
                    window.addWindowListener ( windowAdapter );
                }
            }

            /**
             * Removes window listener.
             */
            protected void removeListener ()
            {
                if ( window != null )
                {
                    window.removeWindowListener ( windowAdapter );
                    window = null;
                }
            }
        } );
    }

    /**
     * Sample main method for runing the example.
     *
     * @param args arguments
     */
    public static void main ( final String[] args )
    {
        SwingUtilities.invokeLater ( new Runnable ()
        {
            @Override
            public void run ()
            {
                final JFrame frame = new JFrame ();

                final SamplePanel panel = new SamplePanel ();
                panel.add ( new JLabel ( "Sample panel content" ) );
                frame.add ( panel );

                frame.pack ();
                frame.setDefaultCloseOperation ( JFrame.DISPOSE_ON_CLOSE );
                frame.setLocationRelativeTo ( null );
                frame.setVisible ( true );
            }
        } );
    }
}

使用此代码,您的面板将在显示时自动在其父窗口上注册窗口侦听器。一旦面板被隐藏或从窗口中删除,它也会自动删除侦听器,因此这可能是您可以拥有的最佳解决方案。

但要小心,如果您将在同一个窗口上多次使用该面板 - 所有实例都将添加自己的侦听器,并且都将分别执行关闭操作。如果您只想在每个窗口/框架/对话框实例中执行一次关闭操作 - 您需要在窗口本身上添加侦听器,最好是在创建它的位置以免使其模糊。

您可能还会注意到,在我的示例中,实际上有一个方法可以直接检索面板的父窗口:

window = SwingUtilities.getWindowAncestor ( SamplePanel.this );

尽管您不能直接在面板中使用它,因为在创建面板的那一刻,它还没有添加到任何容器中,更不用说可见窗口了。这就是为什么需要我展示的带有祖先侦听器的解决方案的原因。


推荐阅读