Java - 如何防止WindowClosing实际关闭窗口

56

我似乎和大多数人的问题相反。我有以下相当标准的代码,用于查看用户是否想在关闭窗口之前进行一些保存:

  frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
  frame.addWindowListener(new WindowAdapter() {
     public void windowClosing(WindowEvent ev) {
      boolean close = true;
         // check some files, asking if the user wants to save
         // YES and NO handle OK, but if the user hits Cancel on any file,
         //   I want to abort the close process     
         // So if any of them hit Cancel, I set "close" to false
      if (close) {
          frame.dispose();
          System.exit(0);
         }
       }            
});
无论我尝试什么,当我从windowClosing中出来时窗口总是关闭。将WindowAdapter更改为WindowListener没有任何区别。奇怪的是,文档明确表示:“如果程序在处理此事件时未显式隐藏或处理窗口,则窗口关闭操作将被取消”,但对我来说并不起作用。有没有其他处理框架上X的方法?TIA

3
如果你能创建一个sscce,尽可能地简化问题,我敢打赌肯定会有一个 bug 很明显,而且如果它仍不明显,那么你可以发布这个 sscce,我们就能更好地帮助你解决问题了。请注意,我的翻译保留了原文的意思和用词,只是让表述更通俗易懂。 - Hovercraft Full Of Eels
2
根据提供的代码,你设置 close 变量的逻辑可能是错误的。由于它默认为 true,看起来你没有正确地重置它。在 if 语句之前,你是否打印出了该变量的值? - camickr
2
我刚遇到了另一种情况,如果使用Netbeans(8.0),可能会导致这些症状。由Design View自动生成的代码将添加其自己的默认关闭操作,这可能会覆盖人工生成的代码中指定的行为。这可以在JDialog属性框中进行编辑。(尽管不是Paul问题的答案,但我留下此评论供未来寻求类似问题解决方案的人们参考。) - John Walthour
7个回答

80

我刚刚尝试了这个最小化测试案例:

import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;
import javax.swing.WindowConstants;

public class Test {

    public static void main(String[] args) {
        final JFrame frame = new JFrame("Test");
        frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent ev) {
                //frame.dispose();
            }
        });
        frame.setVisible(true);
    }

}

如果我将dispose调用保留为注释,并点击关闭按钮,窗口不会退出。取消注释并点击关闭按钮,窗口会关闭。

我猜测你设置“close”变量的逻辑有问题。请再仔细检查一下。


1
谢谢大家!我找到了,确实是我的问题。知道简单的情况下能够正常工作对我帮助很大! - Paul Morrison
1
请学习Java命名规范并坚持遵循它们 - 尽可能使用最短的测试用例,加一分 :-) - kleopatra
1
在上面的演示和其他答案中提到,设置默认关闭操作对我非常关键。 - ajon
干净的答案。+1 - m4heshd

26

我认为这是关键:frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); 在我编写的测试用例中,它产生了差异。


1
这是整个事情的关键。EXIT_ON_CLOSE似乎覆盖了其他答案中提到的所有内容。谢谢Ben! - Mark W

7

不确定您的问题出在哪里,

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class ClosingFrame extends JFrame {

    private JMenuBar MenuBar = new JMenuBar();
    private JFrame frame = new JFrame();
    private static final long serialVersionUID = 1L;
    private JMenu File = new JMenu("File");
    private JMenuItem Exit = new JMenuItem("Exit");

    public ClosingFrame() {
        File.add(Exit);
        MenuBar.add(File);
        Exit.addActionListener(new ExitListener());
        WindowListener exitListener = new WindowAdapter() {

            @Override
            public void windowClosing(WindowEvent e) {
                int confirm = JOptionPane.showOptionDialog(frame,
                        "Are You Sure to Close this Application?",
                        "Exit Confirmation", JOptionPane.YES_NO_OPTION,
                        JOptionPane.QUESTION_MESSAGE, null, null, null);
                if (confirm == JOptionPane.YES_OPTION) {
                    System.exit(1);
                }
            }
        };
        frame.addWindowListener(exitListener);
        frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
        frame.setJMenuBar(MenuBar);
        frame.setPreferredSize(new Dimension(400, 300));
        frame.setLocation(100, 100);
        frame.pack();
        frame.setVisible(true);
    }

    private class ExitListener implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {
            int confirm = JOptionPane.showOptionDialog(frame,
                    "Are You Sure to Close this Application?",
                    "Exit Confirmation", JOptionPane.YES_NO_OPTION,
                    JOptionPane.QUESTION_MESSAGE, null, null, null);
            if (confirm == JOptionPane.YES_OPTION) {
                System.exit(1);
            }
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                ClosingFrame cf = new ClosingFrame();
            }
        });
    }
}

7
不要使用魔术数字。confirm == 0 是什么意思?相反,你应该使用 confirm == JOptionPane.YES_OPTION 更易于理解。 - camickr

5

处理此事情的方法如下:
如果用户选择“是”,则在该if else的大括号内使用setDefaultCloseOperation(DISPOSE_ON_CLOSE);

如果选择取消,则使用setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);

例如:

int safe = JOptionPane.showConfirmDialog(null, "titleDetails!",  "title!!", JOptionPane.YES_NO_CANCEL_OPTION);

if(safe == JOptionPane.YES_OPTION){
    setDefaultCloseOperation(DISPOSE_ON_CLOSE);//yes

} else if (safe == JOptionPane.CANCEL_OPTION) {
    setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);//cancel
} else {
    setDefaultCloseOperation(DISPOSE_ON_CLOSE);//no
}

1
谢谢。如果我将这段代码放在关闭事件中,它将防止对话框关闭。 - Charif DZ

1

我不确定你的问题出在哪里,但这个对我有效!

frame.addWindowListener(new WindowAdapter() {

            public void windowClosing(WindowEvent evt) {
                            int res=JOptionPane.showConfirmDialog(null,
                                    "Do you want to exit.?");
                            if(res==JOptionPane.YES_OPTION){
                                    Cal.this.dispose();
                            }
            }                               
        });

1
为了解决同样的问题,我尝试了这篇文章中的第一个答案。作为单独的应用程序,它可以工作,但在我的情况下却不行。也许区别在于JFrame(在答案中)和FrameView(在我的情况下)。
public class MyApp extends SingleFrameApplication { // application class of my project
  ...
  protected static MyView mainForm; // main form of application
  ... 
}  
public class MyView extends FrameView {
    ...
    //Adding this listener solves the problem. 
    MyApp.getInstance().addExitListener(new ExitListener() {

      @Override
      public boolean canExit(EventObject event) {
        boolean res = false;
        int reply = JOptionPane.showConfirmDialog(null,
                "Are You sure?", "", JOptionPane.YES_NO_OPTION);
        if (reply == JOptionPane.YES_OPTION) {
          res = true;
        }
        return res;
      }
      @Override
      public void willExit(EventObject event) {
      }
    });
    ...
}   

0

setDefaultCloseOperation() 方法可以帮助解决问题。https://chortle.ccsu.edu/java5/Notes/chap56/ch56_9.html

查看此链接


1
虽然仅包含链接的答案也是答案,但最好将解释放在答案中并使用链接作为参考,因为链接可能会失效。 - C8H10N4O2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接