为什么在调用 setVisible(false) 和 dispose() 时调用的 Window/Component 侦听器不同?
Why are the Window/Component Listeners invoked differently when setVisible(false) and dispose() are called?
我看到的差异是(运行 on JDK 1.7):
setVisible(false)
, invokes componentHidden
but not windowClosed
(The API states only on dispose()
so it's OK even if it irritates me)
但是
dispose()
, invokes windowClosed
but not componentHidden
简短 运行 示例代码 (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 最小)。
我考虑过这个post:
JDialog setVisible(false) vs dispose()
- 在答案中似乎应该没有区别,使用
dispose()
...
API 文档:
Window.setVisible(boolean b), Window.dispose(), ComponentListener.componentHidden(ComponentEvent e), WindowListener.windowClosed(WindowEvent e)
我为什么关心:自然是出于好奇,也是因为我使用按钮关闭window(调用dispose()
)和界面也可以通过 top/right window 关闭图标和 alt+F4 (调用 setVisible(false)
! ?)。因此,不能使用上述任何一个侦听器。只有 HierarchyListener
会捕获它们,这似乎违反直觉。
编辑: 这个问题的范围是 "why is it like this"?目的是什么?”。我期待 dispose()
调用两者!我在 API 文档中找不到任何线索来说明为什么不这样做。
the interface can also be close by top/right window close icon alt+F4 (invoking setVisible(false)!?)
这是由默认关闭操作决定的。您可以使用 setDefaultCloseOperation
设置它。默认值为 HIDE_ON_CLOSE
,这就是您获得 componentHidden
调用的原因。如果您将其设置为 DISPOSE_ON_CLOSE
那么您将获得 windowClosed
调用。设置为后者将允许您只注册那些事件类型。
无论如何,隐藏和处置做不同的事情。处置会释放使用的资源,而隐藏则不会。此外,隐藏最后一个 window 不会退出 JVM,而处理它会。
至于事件调度的技术方面,有很多错综复杂的地方。虽然处理 window 确实调用了它的隐藏方法,但事件的调度是在操作完成后完成的。这意味着 EDT 可以调度事件 "after the fact"。由于 window 已关闭,因此不会调度隐藏事件。
我在努力解决所描述的行为时遇到了这个问题。 componentHidden
的处理程序没有被调用,尽管 ComponentEvent(COMPONENT_HIDDEN)
被 setVisible(false)
安排到对话框的事件队列中。
我的对话框是模态的,调用者在对话框关闭后显式调用 dispose
并从 setVisible(true)
调用 returns。这可能是对话框的事件队列和应用程序的事件队列之间的“竞争条件”。因此,我的解决方法是在调用方方面:
SwingUtilities.invokeLater(myDialog::dispose);
这应该推迟对话框的处理,直到其事件队列耗尽; componentHidden
在此设置中被调用。
我看到的差异是(运行 on JDK 1.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 最小)。
我考虑过这个post:
JDialog setVisible(false) vs dispose()
- 在答案中似乎应该没有区别,使用
dispose()
...
API 文档:
Window.setVisible(boolean b), Window.dispose(), ComponentListener.componentHidden(ComponentEvent e), WindowListener.windowClosed(WindowEvent e)
我为什么关心:自然是出于好奇,也是因为我使用按钮关闭window(调用dispose()
)和界面也可以通过 top/right window 关闭图标和 alt+F4 (调用 setVisible(false)
! ?)。因此,不能使用上述任何一个侦听器。只有 HierarchyListener
会捕获它们,这似乎违反直觉。
编辑: 这个问题的范围是 "why is it like this"?目的是什么?”。我期待 dispose()
调用两者!我在 API 文档中找不到任何线索来说明为什么不这样做。
the interface can also be close by top/right window close icon alt+F4 (invoking setVisible(false)!?)
这是由默认关闭操作决定的。您可以使用 setDefaultCloseOperation
设置它。默认值为 HIDE_ON_CLOSE
,这就是您获得 componentHidden
调用的原因。如果您将其设置为 DISPOSE_ON_CLOSE
那么您将获得 windowClosed
调用。设置为后者将允许您只注册那些事件类型。
无论如何,隐藏和处置做不同的事情。处置会释放使用的资源,而隐藏则不会。此外,隐藏最后一个 window 不会退出 JVM,而处理它会。
至于事件调度的技术方面,有很多错综复杂的地方。虽然处理 window 确实调用了它的隐藏方法,但事件的调度是在操作完成后完成的。这意味着 EDT 可以调度事件 "after the fact"。由于 window 已关闭,因此不会调度隐藏事件。
我在努力解决所描述的行为时遇到了这个问题。 componentHidden
的处理程序没有被调用,尽管 ComponentEvent(COMPONENT_HIDDEN)
被 setVisible(false)
安排到对话框的事件队列中。
我的对话框是模态的,调用者在对话框关闭后显式调用 dispose
并从 setVisible(true)
调用 returns。这可能是对话框的事件队列和应用程序的事件队列之间的“竞争条件”。因此,我的解决方法是在调用方方面:
SwingUtilities.invokeLater(myDialog::dispose);
这应该推迟对话框的处理,直到其事件队列耗尽; componentHidden
在此设置中被调用。