如何从代码中关闭Java Swing应用程序


94

从代码终止Swing应用程序的正确方法是什么,陷阱是什么?

我试图在计时器触发后自动关闭我的应用程序。但是,仅仅呼吁dispose()JFrame没有做的伎俩-窗口消失了,但应用程序并没有终止。但是,当使用关闭按钮关闭窗口时,应用程序会终止。我该怎么办?


请发布您的计时器的代码段。
James Schek

Answers:


106

您可以将JFrame的默认关闭操作设置为“ DISPOSE_ON_CLOSE”,而不是EXIT_ON_CLOSE(为什么人们继续使用EXIT_ON_CLOSE不在我的视野之内)。

如果您有未处理的Windows窗口或非守护线程,则您的应用程序不会终止。这应该被认为是一个错误(使用System.exit解决它是一个非常糟糕的主意)。

最常见的罪魁祸首是java.util.Timer和您创建的自定义线程。两者都应设置为守护程序,或者必须将其显式杀死。

如果要检查所有活动帧,可以使用Frame.getFrames()。如果所有Windows /框架都已废弃,请使用调试器检查是否仍在运行任何非守护线程。


就我而言,我在调试器中发现我的Swingworker仍处于活动状态。我在WindowClose Eventlistener中调用了它的cancel(true)方法,该程序现在终止。谢谢!
汉斯·彼得·斯特尔2009年

请注意,您可能必须在每个帧上调用dispose,通常这是“足够的”(尽管将默认关闭动作设置为EXIT_ON_CLOSE也不是坏主意)。
rogerdpack

如果您有一个窗口打开另一个窗口,但又没有将其自身放置以便可以将其用于back窗口,该怎么办?如果第二个窗口,然后关闭并使用DISPOSE_ON_CLOSE该程序不会终止,因为第一个窗口仍然是“未予处置” ...有没有解决这个办法没有DISPOSE_ON_CLOSE
Svend Hansen 2012年

第一个窗口应将自身添加为第二个窗口的侦听器,并采取适当的措施。
詹姆斯·谢克

3
使用EXIT_ON_CLOSE将强制终止该应用程序。如果需要在程序退出之前采取措施(例如保存工作数据),则必须利用JVM事件处理程序,而不仅仅是使用常规的swing事件处理程序。两者都将“起作用”,但是EXIT_ON_CLOSE将为更复杂的应用程序带来问题。
詹姆斯·谢克

34

我猜是EXIT_ON_CLOSE

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

before System.exit(0)更好,因为您可以在实际离开应用程序之前编写Window Listener进行一些清理操作。

该窗口侦听器允许您定义:

public void windowClosing(WindowEvent e) {
    displayMessage("WindowListener method called: windowClosing.");
    //A pause so user can see the message before
    //the window actually closes.
    ActionListener task = new ActionListener() {
        boolean alreadyDisposed = false;
        public void actionPerformed(ActionEvent e) {
            if (frame.isDisplayable()) {
                alreadyDisposed = true;
                frame.dispose();
            }
        }
    };
    Timer timer = new Timer(500, task); //fire every half second
    timer.setInitialDelay(2000);        //first delay 2 seconds
    timer.setRepeats(false);
    timer.start();
}

public void windowClosed(WindowEvent e) {
    //This will only be seen on standard output.
    displayMessage("WindowListener method called: windowClosed.");
}

16

尝试:

System.exit(0);

粗暴,但有效。


不幸的是,这对我来说太粗糙了。我希望对某些关闭操作处理窗口关闭事件。好的,我可以使用SwingUtils.invokeLater来执行System.exit,但是我宁愿做适当的事情。
汉斯·彼得·斯托尔

5
System.exit(0)不仅很粗糙,而且很邪恶。检查所有框架,呼叫处置。如果失败,请运行调试器,并查看哪些非守护线程仍然存在。
James Schek

即使在JDK中,也存在许多错误,这些错误会拖延整个过程。因此+1以退出(),但您可能想在调试版本中将其禁用。
Tom Hawtin-大头钉

11

可能安全的方法是这样的:

    private JButton btnExit;
    ...
    btnExit = new JButton("Quit");      
    btnExit.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e){
            Container frame = btnExit.getParent();
            do 
                frame = frame.getParent(); 
            while (!(frame instanceof JFrame));                                      
            ((JFrame) frame).dispose();
        }
    });

3
Frame用大写字母命名变量的方式非常糟糕,就像类的名称一样……
Jean-Philippe Pellet 2012年

非常感谢!这是最好的方法之一!
rzaaeeff '16

9

以下程序包括一些代码,这些代码将在没有显式调用System.exit()的情况下终止缺少外部线程的程序。为了将此示例应用于使用线程/侦听器/计时器/等的应用程序,只需在actionPerformed()中手动启动WindowEvent之前,插入插入清理代码即可请求(并在可能的情况下等待)其终止。

对于那些希望能够复制/粘贴能够完全按照所示方式运行的代码的人,最后包括一个有点丑陋但不相关的main方法。

public class CloseExample extends JFrame implements ActionListener {

    private JButton turnOffButton;

    private void addStuff() {
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        turnOffButton = new JButton("Exit");
        turnOffButton.addActionListener(this);
        this.add(turnOffButton);
    }

    public void actionPerformed(ActionEvent quitEvent) {
        /* Iterate through and close all timers, threads, etc here */
        this.processWindowEvent(
                new WindowEvent(
                      this, WindowEvent.WINDOW_CLOSING));
    }

    public CloseExample() {
        super("Close Me!");
        addStuff();
    }

    public static void main(String[] args) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                CloseExample cTW = new CloseExample();
                cTW.setSize(200, 100);
                cTW.setLocation(300,300);
                cTW.setVisible(true);
            }
        });
    }
}

4

如果我对您的理解正确,即使用户没有单击关闭按钮,也要关闭该应用程序。您可能需要使用更适合您的需要的addWindowListener()或enableEvents()注册WindowEvents。

然后,您可以通过调用processWindowEvent()来调用事件。这是一个示例代码,它将创建一个JFrame,等待5秒钟,然后在没有用户交互的情况下关闭JFrame。

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

public class ClosingFrame extends JFrame implements WindowListener{

public ClosingFrame(){
    super("A Frame");
    setSize(400, 400);
            //in case the user closes the window
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setVisible(true);
            //enables Window Events on this Component
            this.addWindowListener(this);

            //start a timer
    Thread t = new Timer();
            t.start();
    }

public void windowOpened(WindowEvent e){}
public void windowClosing(WindowEvent e){}

    //the event that we are interested in
public void windowClosed(WindowEvent e){
    System.exit(0);
}

public void windowIconified(WindowEvent e){}
public void windowDeiconified(WindowEvent e){}
public void windowActivated(WindowEvent e){}
public void windowDeactivated(WindowEvent e){}

    //a simple timer 
    class Timer extends Thread{
           int time = 10;
           public void run(){
     while(time-- > 0){
       System.out.println("Still Waiting:" + time);
               try{
                 sleep(500);                     
               }catch(InterruptedException e){}
             }
             System.out.println("About to close");
    //close the frame
            ClosingFrame.this.processWindowEvent(
                 new WindowEvent(
                       ClosingFrame.this, WindowEvent.WINDOW_CLOSED));
           }
    }

    //instantiate the Frame
public static void main(String args[]){
          new ClosingFrame();
    }

}

如您所见,processWindowEvent()方法会在您有机会在关闭应用程序之前进行清理代码的地方触发WindowClosed事件。


windowClosed应该调用dispose()而不是System.exit(0)。
James Schek

2

看一下Oracle文档

从JDK 1.4开始,如果满足以下条件,则应用程序终止:

  • 没有可显示的AWT或Swing组件。
  • 本机事件队列中没有本机事件。
  • java EventQueues中没有AWT事件。

角箱:

该文档指出,某些软件包会创建可显示的组件而不释放它们。调用Toolkit.getDefaultToolkit()的程序不会终止。以其他示例为例。

当其他进程出于某种原因将事件发送到本机事件队列中时,它们也可以使AWT保持活动状态。

我还注意到,在某些系统上,应用程序实际终止需要花费几秒钟的时间。


0

我认为,这里的想法是WindowListener-您可以在事情关闭之前在其中添加任何您想运行的代码


0

作为对其他评论的回应,DISPOSE_ON_CLOSE似乎无法正确退出应用程序-它只会破坏窗口,但应用程序将继续运行。如果要终止应用程序,请使用EXIT_ON_CLOSE。


这个回答暗示了詹姆斯·舍克的回答恰恰相反。哪一个是正确的?(当我使用一个简单的应用程序进行测试时,两者似乎都可以工作...)
OR Mapper

不记得我现在如何测试了。
JSideris
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.