我正在编写一个脚本,其中涉及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”方法下放置例外e ,我在关闭窗口的“X”按钮时会得到以下输出(省略内部调用):< / p>
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(如果您在覆盖'dispose'方法下注释掉前两行关于异常堆栈跟踪打印,则最佳可见并观看输出。)
如果您想使用/查看并且事先感谢您,这是一个硬剥离的版本!
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();
}
}
}
可能有用的信息:
- &GT; private boolean dispos = false;
然后在调用dispose方法时进行检查:
@Override
public void dispose() {
if (!disposed) {
disposed = true;
super.dispose();
}
}
虽然它可以解决问题,但它远非一个好的答案,未来的问题可能很容易存在,因为核心没有得到妥善修复。
答案 0 :(得分:1)
父窗口包含对话框的引用,并在对话本身处理时重新处理对话框。
您的问题是您没有为对话框分配父窗口,因此出于某种原因,当对话框被丢弃时,它会重新处理以前创建的所有对话框引用,就像基类保存对象的引用一样。孩子的窗户。您可以通过将父窗口传递到对话框的超级构造函数来解决问题,如下所示:
import javax.swing.*;
import java.awt.Window;
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(Window win) {
super(win);
setModal(true);
}
// Overrides and calls (super)dispose method of JDialog - Nothing
// unusual
@Override
public void dispose() {
Exception e = new Exception();
// e.printStackTrace();
String text = String.format("Disposing. This hashCode: %08X", hashCode());
System.out.println(text);
super.dispose();
}
}
static class CaptureDialog extends BaseDialog implements ActionListener {
CaptureDialog(Window win) {
super(win);
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(MainForm.this);
}
}
}
我自己,如果我认为我可能需要它,我会避免重新创建对话框,这样可以防止不必要的引用累积。请参阅下面的代码并注释并取消注释显示的部分以了解我的意思:
import java.awt.Window;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class MainSimple extends JPanel {
private JDialog dialog;
public MainSimple() {
add(new JButton(new OpenDialogAction("Open Dialog", KeyEvent.VK_O)));
add(new JButton(new DisposeAction("Exit", KeyEvent.VK_X)));
}
private class OpenDialogAction extends AbstractAction {
public OpenDialogAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
@Override
public void actionPerformed(ActionEvent e) {
boolean test = true;
// test = (dialog == null); // ***** comment or uncomment this line *****
if (test) {
Window win = SwingUtilities.getWindowAncestor(MainSimple.this);
dialog = new MyDialog(win);
dialog.pack();
dialog.setLocationRelativeTo(win);
}
dialog.setVisible(true);
}
}
private class MyDialog extends JDialog {
public MyDialog(Window win) {
super(win, "My Dialog", ModalityType.APPLICATION_MODAL);
add(new JButton(new DisposeAction("Close", KeyEvent.VK_C)));
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
}
@Override
public void dispose() {
String text = String.format("Disposing. This hashCode: %08X", hashCode());
System.out.println(text);
super.dispose();
}
}
private class DisposeAction extends AbstractAction {
public DisposeAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
@Override
public void actionPerformed(ActionEvent e) {
Component source = (Component) e.getSource();
Window win = SwingUtilities.getWindowAncestor(source);
win.dispose();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui() {
MainSimple mainPanel = new MainSimple();
JFrame frame = new JFrame("Main");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
}
再次注意,父JFrame保存对创建的所有对话框的引用,无论它们是否已被处置,并在关闭时重新处理它们。
答案 1 :(得分:0)
有点晚了,但我仍然认为它会对某人有所帮助。
我遇到了同样的问题,并检查了我为没有参数的构造函数发现的 JDialog
文档说
注意:此构造函数不允许您创建无主 JDialog。要创建无主 JDialog,您必须使用参数为 null 的 JDialog(Window) 或 JDialog(Dialog) 构造函数。
所以我只是尝试使用 JDialog(Window)
或 JDialog(Dialog)
并且成功了!
我只需要写这段代码
public class MyDialog extends JDialog {
public MyDialog() {
super((Window)null);
}
}
如果您无法访问应该是父级的 JFrame(这是我的情况),这可能会有所帮助