我意识到正式的方法是侦听添加到 JFrame 主机的窗口关闭事件,然后简单地在 JPanel 上调用清理方法。然而,我很好奇。我最近才在我的面板中获得了关闭(关闭、离开、现在离开(钩子的需求,该钩子已经在我的程序中使用。而且,出于好奇,我不想重新访问这个面板被放置在通用旧 JFrame(不需要特殊处理(中的地方,并且它只是显示为一个对话框,等待输入,然后被关闭。我不想让这个假设的其他程序员(我(去向那些已经使用我的面板的帧添加窗口侦听器,要求他们现在调用新的关闭方法。面板中的代码需要添加功能,那么为什么要让那些 Framer 都去更改他们的代码来添加窗口侦听器呢?难道一个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);
}
});
}
}
我不知道这是否是规范的做事方式,但是对于 AncestorListener,如果保存组件的主窗口被调用的 ancestorAdd 方法设置为可见,您会收到通知。发生这种情况时,您可以通过SwingUtilities.getWindowAncestor(...)
获取窗口祖先,然后将所需的任何侦听器添加到此窗口。例如:
包装 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);
}
}
我想一个组件监听器,对componentShown(ComponentEvent ce)
做出反应也可以做到这一点。
你确定要做你正在做的事情吗?
首先,此代码显然不起作用。在我的系统上,"表单已关闭"从不打印。
其次,我在 istener 中捕获的是"layeredContainerLayer"
,当窗口打开时"ancestor"
属性会发生变化。"ancestor"
改变可能是你想要的,或多或少,也许?
但是,您能否确保只按该顺序触发单个"layeredContainerLayer"
源事件,或者它只发生一次,或者没有其他事件被传播?即使你深入挖掘以真正了解正在发生的事情,以及以什么顺序,仍然不要这样做。这是一个丑陋的黑客。
也许实现一些依赖于Runtime.getRuntime().addShutdownHook(...)
和您自己的听众的东西,通知任何想要收到关闭通知的人。