java调用setVisible(false)和dispose()时,为什么窗口/组件侦听器的调用方式不同?
我看到的区别是(在JDK1.7上运行):
setVisible(false)
, invokescomponentHidden
but notwindowClosed
(The API states only ondispose()
so it's OK even if it irritates me)
但是
dispose()
, invokeswindowClosed
but notcomponentHidden
短运行示例代码(MCVE):
public class JDialogTest extends JDialog {
private static final long serialVersionUID = 1L;
public JDialogTest(JFrame owner){
super(owner,ModalityType.APPLICATION_MODAL);
init();
}
private void init() {
this.getContentPane().setLayout(new GridLayout(1,2));
JButton btnVisible = new JButton("Set visible false");
btnVisible.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JDialogTest.this.setVisible(false);
}
});
JButton btnDispose = new JButton("Dispose");
btnDispose.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JDialogTest.this.dispose();
}
});
this.getContentPane().add(btnVisible);
this.getContentPane().add(btnDispose);
this.pack();
}
public static void main(String[] args) {
//A fake frame to test JDialog
JFrame fakeFrame = new JFrame("Fake Frame");
fakeFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
fakeFrame.getContentPane().setLayout(new BorderLayout());
JButton btnOpen = new JButton("Open Dialog");
fakeFrame.getContentPane().add(btnOpen,BorderLayout.CENTER);
fakeFrame.pack();
fakeFrame.setLocationRelativeTo(null);
//Generate the test dialog
final JDialogTest dialog = new JDialogTest(fakeFrame);
dialog.addComponentListener(new ComponentAdapter() {
@Override
public void componentShown(ComponentEvent e) {
System.out.println("Component Shown");
}
@Override
public void componentHidden(ComponentEvent e) {
System.out.println("Component Hidden");
}
});
dialog.addWindowListener(new WindowAdapter() {
@Override
public void windowOpened(WindowEvent e) {
System.out.println("Window open");
}
@Override
public void windowClosed(WindowEvent e) {
System.out.println("Window closed");
}
});
dialog.setLocationRelativeTo(null);
btnOpen.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
dialog.setVisible(true);
}
});
fakeFrame.setVisible(true);
}
}
注意:这个例子的特点是JDialog
,但我在JFrame
中看到了相同的行为,即测试简单的将侦听器附加到fakeFrame
,并添加类似的按钮。(在MVCE中避免,以使其M最小)
我考虑过这个职位:
JDialog setVisible(false) vs dispose()
- 在回答似乎是应该没有区别,使用
dispose()
李>
API文档:
Window.setVisible(boolean b)、Window.dispose()、ComponentListener.componentHidden(ComponentEvent e)、WindowListener.windowClosed(WindowEvent e)
我为什么要关心:自然是出于好奇,但也因为我使用按钮关闭窗口(调用^{HierarchyListener
会同时捕获它们,这似乎违反直觉
编辑:问题的范围是“为什么会这样”?目的何在?“。我希望dispose()
同时调用这两个!我在API文档中找不到任何线索来解释为什么不调用
# 1 楼答案
我是在与所描述的行为作斗争时遇到这个问题的。虽然
setVisible(false)
已将ComponentEvent(COMPONENT_HIDDEN)
调度到对话框的事件队列,但未调用我的componentHidden
处理程序我的对话框是模态的,调用方在对话框关闭并从
setVisible(true)
返回后显式调用dispose
。这可能是对话框的事件队列和应用程序的事件队列之间的“竞争条件”。因此,我的工作是在打电话的一方:这将推迟对话框的处理,直到其事件队列耗尽^在此设置中调用{}
# 2 楼答案
这由默认的关闭操作确定。您可以使用
setDefaultCloseOperation
设置它。默认值为HIDE_ON_CLOSE
,这就是为什么会得到componentHidden
调用。如果将其设置为DISPOSE_ON_CLOSE
,则将得到一个windowClosed
调用。设置为后者将允许您仅注册这些事件类型不管怎样,隐藏和处置做不同的事情。释放释放隐藏时使用的资源不会。此外,隐藏最后一个窗口不会在释放时退出JVM
至于事件调度的技术方面,有很多复杂之处。当处理窗口调用其隐藏方法时,事件的调度在操作完成后完成。这意味着EDT可以“事后”调度事件。由于窗口已关闭,因此它不会分派隐藏事件