gpt4 book ai didi

Java - 多次调用自定义 JDialog 处理方法 - 它不打算这样做

转载 作者:行者123 更新时间:2023-11-30 10:41:21 25 4
gpt4 key购买 nike

我正在编写一个脚本,其中涉及连续弹出 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();
}
}
}

如果我运行应用程序然后打开和关闭/处理对话框,问题就很明显了。通过将 Exception e 放置在 BaseDialog 的“dispose”方法下,我在通过窗口的“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(如果您在覆盖的“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();
}
}
}

可能有用的信息:

  1. 省略“super.dispose()”会导致“dispose”仅被调用一次 - 应用程序代码不应成为问题。
  2. 如果我扩展 JFrame 而不是 JDialog(关于 BaseDialog 类),则会正确调用 dispose 方法(使用 super.dispose())。
  3. 有点无关紧要,但“hack”是在 BaseDialog 类下创建一个私有(private)字段:

-> private boolean disposed = false;

然后在调用dispose方法时进行检查:

@Override
public void dispose() {
if (!disposed) {
disposed = true;
super.dispose();
}
}

虽然它可能会解决问题,但它远非一个好的答案,而且由于核心未正确修复, future 很容易出现问题。

最佳答案

父窗口持有对对话框的引用,并在对话框本身被处置时重新处置该对话框。

您的问题是您没有为对话框分配父窗口,因此由于某种原因,当对话框被处置时,它会重新处置先前创建的所有对话框引用,就好像基类持有对子项的引用一样 window 。您可以通过将父窗口传递给对话框的 super 构造函数来解决这个问题,如下所示:

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 保留对所有创建的对话框的引用,无论它们是否已被释放,并在关闭时重新释放它们。

关于Java - 多次调用自定义 JDialog 处理方法 - 它不打算这样做,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38517063/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com