【发布时间】:2016-07-22 02:03:01
【问题描述】:
我正在编写一个脚本,其中涉及连续弹出 JDialogs 以要求用户捕获屏幕上的信息(例如菜单周围的框等),以便程序随后自动单击我指定的位置。
我目前遇到的问题是,当我关闭自定义 JDialog 时,dispose 方法似乎被多次调用,尽管我不知道为什么。
这是该问题的完整工作示例:
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Main {
// Creates the main frame (MainForm extends JFrame)
private static MainForm mainForm = new MainForm();
public static void main(String[] args) {
mainForm.setVisible(true);
}
static class BaseDialog extends JDialog {
BaseDialog() {
super();
setModal(true);
}
// Overrides and calls (super)dispose method of JDialog - Nothing unusual
@Override
public void dispose() {
Exception e = new Exception();
e.printStackTrace();
System.out.println("disposing");
super.dispose();
}
}
static class CaptureDialog extends BaseDialog implements ActionListener {
CaptureDialog() {
super();
JButton btnInventory = new JButton("Close Me");
btnInventory.addActionListener(this);
add(btnInventory);
setTitle("Recapture");
setModalityType(ModalityType.APPLICATION_MODAL);
setLocationRelativeTo(null);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setResizable(false);
setSize(200, 80);
setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Clicked the button!");
dispose();
}
}
static class MainForm extends JFrame implements ActionListener {
MainForm() {
super("Example");
JButton btnCapture = new JButton();
btnCapture.setText("Capture");
btnCapture.addActionListener(this);
add(btnCapture);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setSize(200, 80);
}
// Only one button is added to action listener ('if' not necessary)
@Override
public void actionPerformed(ActionEvent e){
new CaptureDialog();
}
}
}
如果我运行应用程序然后打开和关闭/处理对话框,问题就很明显了。通过在 BaseDialog 的“dispose”方法下放置 Exception e,我在通过窗口的“X”按钮关闭时得到以下输出(省略内部调用):
java.lang.Exception
at Main$BaseDialog.dispose(Main.java:24)
at javax.swing.JDialog.processWindowEvent(JDialog.java:691)
at java.awt.Window.processEvent(Window.java:2017)
at java.awt.WaitDispatchSupport$2.run(WaitDispatchSupport.java:184)
at java.awt.WaitDispatchSupport$4.run(WaitDispatchSupport.java:229)
at java.awt.WaitDispatchSupport$4.run(WaitDispatchSupport.java:227)
at java.awt.WaitDispatchSupport.enter(WaitDispatchSupport.java:227)
at java.awt.Dialog.show(Dialog.java:1084)
at java.awt.Component.show(Component.java:1673)
at java.awt.Component.setVisible(Component.java:1625)
at java.awt.Window.setVisible(Window.java:1014)
at java.awt.Dialog.setVisible(Dialog.java:1005)
at Main$CaptureDialog.<init>(Main.java:46)
at Main$MainForm.actionPerformed(Main.java:71)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
disposing
disposing
java.lang.Exception
at Main$BaseDialog.dispose(Main.java:24)
at java.awt.Window.disposeImpl(Window.java:1161)
at java.awt.Window$1DisposeAction.run(Window.java:1189)
at java.awt.Window.doDispose(Window.java:1210)
at java.awt.Window.dispose(Window.java:1151)
at javax.swing.SwingUtilities$SharedOwnerFrame.dispose(SwingUtilities.java:1814)
at javax.swing.SwingUtilities$SharedOwnerFrame.windowClosed(SwingUtilities.java:1792)
at java.awt.Window.processWindowEvent(Window.java:2061)
at javax.swing.JDialog.processWindowEvent(JDialog.java:683)
at java.awt.Window.processEvent(Window.java:2017)
还请注意,如果您运行应用程序并重复“打开 - 关闭”对话框,则该方法调用会以 1 递增(如果您注释掉关于异常堆栈跟踪打印的覆盖的“处置”方法下的前两行,则最明显并观察输出)。
如果您想使用/查看,这是一个硬剥离版本,首先感谢您!
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Main {
public static void main(String[] args) {
new MainForm();
}
static class BaseDialog extends JDialog {
BaseDialog() {
super();
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setVisible(true);
}
@Override
public void dispose() {
new Exception().printStackTrace();
System.out.println("disposing");
super.dispose();
}
}
static class MainForm extends JFrame implements ActionListener {
MainForm() {
super();
JButton btnCapture = new JButton();
btnCapture.setText("Capture");
btnCapture.addActionListener(this);
add(btnCapture);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setSize(200, 80);
setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e){
new BaseDialog();
}
}
}
可能有用的信息:
- 省略“super.dispose()”会导致“dispose”仅被调用一次 - 应用程序代码不应成为问题。
- 如果我扩展 JFrame 而不是 JDialog(关于 BaseDialog 类),则正确调用 dispose 方法(使用 super.dispose())。
- 有点不相关,但“黑客”是在 BaseDialog 类下创建一个私有字段:
-> 私有布尔处理 = false;
然后在调用dispose方法时进行检查:
@Override
public void dispose() {
if (!disposed) {
disposed = true;
super.dispose();
}
}
虽然它可以解决问题,但它远不是一个好的答案,而且由于核心没有正确修复,未来很容易出现问题。
【问题讨论】:
-
我无法回复,但现在我在这里。我重新格式化了代码(昨天我做得不够快,因为我不得不起床并且厌倦了尝试解决问题)并上传了一个简短的工作示例。现在应该不会像以前那样混乱了。
-
从 dispose 方法中打印出
hashCode()以查看正在调用的实例。每次新实例被调用两次,每个旧实例被调用一次。 -
你可能需要深入研究源代码来解决这个问题,因为我还看不出它发生的原因。
-
目前正在尝试通过它,到目前为止我很不走运。我试图在不同的地方使用大量断点来定位罪魁祸首,但和以前一样,还没有运气。有人可能会提到,如果我省略“super.dispose()”,覆盖的方法会被调用一次,所以应用程序本身应该消除代码本身的缺陷,我开始怀疑是否存在核心库某处的问题...
-
我的意思是浏览 Java 核心库源代码