Java 获取JPanel的主机JFrame关闭时的钩子,而不使用窗口关闭事件

Java 获取JPanel的主机JFrame关闭时的钩子,而不使用窗口关闭事件,java,swing,Java,Swing,我意识到正式的方法是监听添加到JFrame主机的窗口关闭事件,然后简单地调用JPanel上的清理方法。然而,我感到好奇。我最近才意识到关闭、离开、离开的必要性,我的程序中已经使用了我的面板中的钩子。而且,出于好奇,我不想再去那些地方,在那里这个面板被放进一个普通的老JFrame中,不需要特殊的处理,它只是显示为一个对话框,等待输入,然后在输入后被关闭。我不想让这个假想的其他程序员给那些已经使用我的面板的帧添加窗口侦听器,要求它们现在调用一个新的关闭方法。面板中的代码需要添加功能,那么为什么要让这

我意识到正式的方法是监听添加到JFrame主机的窗口关闭事件,然后简单地调用JPanel上的清理方法。然而,我感到好奇。我最近才意识到关闭、离开、离开的必要性,我的程序中已经使用了我的面板中的钩子。而且,出于好奇,我不想再去那些地方,在那里这个面板被放进一个普通的老JFrame中,不需要特殊的处理,它只是显示为一个对话框,等待输入,然后在输入后被关闭。我不想让这个假想的其他程序员给那些已经使用我的面板的帧添加窗口侦听器,要求它们现在调用一个新的关闭方法。面板中的代码需要添加功能,那么为什么要让这些框架构建者都去更改代码以添加窗口侦听器呢?难道JPanel不能自己发现这一点吗

因此,我对JPanel进行了一次黑客攻击,以便在JFrame不需要窗口侦听器的情况下检测它何时被关闭。对我来说,JPanel现在更具自我意识了。。。它有自己的窗口关闭检测策略,独立于使用我的JPanel的编码器,需要编写侦听器和调用关闭挂钩。我只是想尝试这样做,而不必返回并更改现有代码

也要意识到,我的黑客只在DISPOSE_ON_CLOSE时有效,但是。。。这就是我在对话中使用的内容

有人能告诉我该怎么做吗?有什么我可以挖掘的财产事件吗?这一定是我刚才所做的一次非常激烈的进攻。肯定是大错特错了。然而,我有我的自我意识JPanel关机钩子,它可以工作。有人请把我带到其他地方,而不用使用它自己的窗口关闭事件来选择父JFrame,我想看看JPanel是否能够自己意识到这一点

我的黑客作品。。。告诉我有什么问题。它肯定是错的,即使它对我起作用。对吧?

以下代码段是一个正在运行的模型

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;

public class JPanelClosing extends JPanel {

    static JFrame frame; // This frame is only here for the mmockup ... what
                         // follows after would be part of your own custom JPanel.

    private boolean formClosing = false;
    private boolean filterEvent = true;

    public JPanelClosing() {
        initComponents();
    }

    private void initComponents() {
        addPropertyChangeListener(new java.beans.PropertyChangeListener() {
            @Override
            public void propertyChange(java.beans.PropertyChangeEvent evt) {
                formPropertyChange(evt);
            }
        });
    }

    private void formPropertyChange(java.beans.PropertyChangeEvent evt) {                                    

        // This is a hack I came up with. The JPanel fires two events when
        // used in a waiting input dialog of an unkown JFrame that hosts it.
        // When the JFrame DefaultCloseOperation is set to DISPOSE_ON_CLOSE:
        // PropertyChangeEvent fires twice when it opens, and twice when it closes.

        // So, I filter out the two events to pick one, like using !valueIsAdjusting.
        // Then, I filter whether it's state one, opening, or state two, closing.
        // This is all kept track of using two field variables; filterEvent, and formClosing 

        // With DISPOSE_ON_CLOSE, (on my machine) I get:
        // Form opened.
        // Form Closed.

        // (EXIT_ON_CLOSE and HIDE_ON_CLOSE will only produce 'Form opened')

        if (!filterEvent) {
            if ( formClosing ) {
                System.out.println("Form Closed.");
                System.exit(0);
            } else {
                formClosing = true;
                System.out.println("Form opened.");
            }
            filterEvent = true;
        } else { // end if value not adjusting
            filterEvent = false;
        }

    }

    public static void main (String args[] ) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                frame = new JFrame();
                final JPanel panel = new JPanelClosing();
                frame.setContentPane(panel);
                frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
                frame.setVisible(true);
            }
        });
    }
}
你确定要做你正在做的事吗

首先,这段代码显然不起作用。在我的系统窗体上关闭。从不打印

其次,我在istener中捕捉到的是layeredContainerLayer,当窗口打开时,祖先属性会发生更改。祖先的改变可能是你想要的,或多或少,也许

但您能否确保只有单层ContainerLayer源事件按该顺序触发,或者它只发生一次,或者其他任何事件都不会传播?即使你挖得足够深,能够真正理解发生了什么,以及发生的顺序,也不要这样做。这是一个丑陋的黑客


可能实现一些依赖于Runtime.getRuntime.addShutdownHook的东西。。。你自己的监听器会通知任何想要得到关机通知的人。

我不知道这是否是一种标准的处理方式,但是对于AncestorListener,如果调用的ancestorAdded方法设置了可查看的主窗口,就会通知你。当这种情况发生时,您可以通过SwingUtilities.GetWindowSenator获取窗口祖先。。。然后将您想要的任何侦听器添加到此窗口。例如:

包装pkg1

import java.awt.Dimension;
import java.awt.Window;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.*;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;

@SuppressWarnings("serial")
public class TestClosing extends JPanel {
    public TestClosing() {
        setPreferredSize(new Dimension(500, 400));

        // addPropertyChangeListener(evt -> System.out.println(evt));

        addAncestorListener(new MyAncestorListener());
    }


    private class MyAncestorListener implements AncestorListener {

        @Override
        public void ancestorAdded(AncestorEvent ae) {
            Window window = SwingUtilities.getWindowAncestor(TestClosing.this);
            if (window != null) {
                window.addWindowListener(new MyWindowListener());
            }
        }

        @Override
        public void ancestorMoved(AncestorEvent ae) {}

        @Override
        public void ancestorRemoved(AncestorEvent ae) {}

    }

    private class MyWindowListener extends WindowAdapter {
        @Override
        public void windowClosed(WindowEvent e) {
            // TODO desired actions
            System.out.println("window closed");
        }

        @Override
        public void windowClosing(WindowEvent e) {
            // TODO desired actions
            System.out.println("window closing");
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }

    private static void createAndShowGui() {
        TestClosing mainPanel = new TestClosing();
        JFrame frame = new JFrame("Test Closing");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.add(mainPanel);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }
}

我想对componentShownComponentEvent ce作出反应的ComponentListener也可以做到这一点。

使用AnceStoreEvent怎么样?谢谢,我会检查一下。它说它可以检测到:祖先组件被从可见对象的层次结构中删除,并且不再显示。也许这样行。我会玩它,如果我发现它更正式,我会发回。我知道这是一个丑陋的黑客。这就是我问方向的原因。我想我只需要添加窗口侦听器。我想如果JPanel能够可靠地知道这一点,我们会在库中看到一个调用。这就是我问的原因。我将只向框架添加窗口关闭事件,并在面板上调用清理方法。新要求。谢谢你的建议。我要玩这个。显然,只听框架上的窗口关闭事件是最直接的选择。我只是想知道其他人是否知道JPanel如何做到这一点,同时只对自己的源代码进行更改。你的方式在我的机器上产生了效果,谢谢你,像其他人一样,把我引导到AnceStoreEvent。以前从未使用过它,这将是我的介绍。有趣的反馈:我更信任的是,您的方式得到的结果与我的方式类似,因为只有在关闭时释放才会导致调用windowClosed和windowClosed。隐藏和退出仅触发windowClosing,而从不调用windowClosing。我的行为也是如此,这只是DISPOSE\u ON\u CLOSE场景的附加行为。有道理。。。离开只是离开,隐藏永远不会离开。。。因此,两者都只产生“关闭”。但是,Dispose确实离开了,但是系统还没有退出,所以我们可以看到关闭事件的发生。但是我的 哈克的行为方式也完全相同。有意思