简体   繁体   English

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

[英]How to close a Java Swing application from the code

What is the proper way to terminate a Swing application from the code, and what are the pitfalls? 从代码中终止Swing应用程序的正确方法是什么,有哪些陷阱?

I'd tried to close my application automatically after a timer fires. 我试图在计时器启动后自动关闭我的应用程序。 But just calling dispose() on the JFrame didn't do the trick - the window vanished but the application did not terminate. 但是只是在JFrame上调用dispose()没有做到这一点 - 窗口消失但应用程序没有终止。 However when closing the window with the close button, the application does terminate. 但是,当使用关闭按钮关闭窗口时,应用程序会终止。 What should I do? 我该怎么办?

Your JFrame default close action can be set to " DISPOSE_ON_CLOSE " instead of EXIT_ON_CLOSE (why people keep using EXIT_ON_CLOSE is beyond me). 您的JFrame默认关闭操作可以设置为“ DISPOSE_ON_CLOSE ”而不是EXIT_ON_CLOSE (为什么人们继续使用EXIT_ON_CLOSE超出我的范围)。

If you have any undisposed windows or non-daemon threads, your application will not terminate. 如果您有任何未曝光的窗口或非守护程序线程,您的应用程序将不会终止。 This should be considered a error (and solving it with System.exit is a very bad idea). 这应该被认为是一个错误(并使用System.exit解决它是一个非常糟糕的主意)。

The most common culprits are java.util.Timer and a custom Thread you've created. 最常见的罪魁祸首是java.util.Timer和你创建的自定义线程。 Both should be set to daemon or must be explicitly killed. 两者都应该设置为守护进程或必须被明确杀死。

If you want to check for all active frames, you can use Frame.getFrames() . 如果要检查所有活动帧,可以使用Frame.getFrames() If all Windows/Frames are disposed of, then use a debugger to check for any non-daemon threads that are still running. 如果处理掉所有Windows /帧,则使用调试器检查仍在运行的任何非守护程序线程。

I guess a EXIT_ON_CLOSE 我想一个EXIT_ON_CLOSE

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

before System.exit(0) is better since you can write a Window Listener to make some cleaning operations before actually leaving the app. System.exit(0)之前更好,因为您可以在实际离开应用程序之前编写一个Window Listener来进行一些清理操作。

That window listener allows you to defined: 那个窗口监听器允许你定义:

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.");
}

Try: 尝试:

System.exit(0);

Crude, but effective. 原油,但有效。

May be the safe way is something like: 可能是安全的方式是这样的:

    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();
        }
    });

The following program includes code that will terminate a program lacking extraneous threads without explicitly calling System.exit(). 以下程序包括将在没有显式调用System.exit()的情况下终止缺少无关线程的程序的代码。 In order to apply this example to applications using threads/listeners/timers/etc, one need only insert cleanup code requesting (and, if applicable, awaiting) their termination before the WindowEvent is manually initiated within actionPerformed(). 为了将此示例应用于使用线程/侦听器/定时器/等的应用程序,在actionPerformed()中手动启动WindowEvent之前,只需要插入清除代码请求(以及,如果适用,等待)它们的终止。

For those who wish to copy/paste code capable of running exactly as shown, a slightly-ugly but otherwise irrelevant main method is included at the end. 对于那些希望复制/粘贴能够完全按照所示运行的代码的人来说,最后会包含一个稍微丑陋但不相关的主要方法。

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);
            }
        });
    }
}

If I understand you correctly you want to close the application even if the user did not click on the close button. 如果我理解正确,即使用户没有点击关闭按钮,也要关闭应用程序。 You will need to register WindowEvents maybe with addWindowListener() or enableEvents() whichever suits your needs better. 您可能需要使用addWindowListener()或enableEvents()注册WindowEvents,以更好地满足您的需求。

You can then invoke the event with a call to processWindowEvent(). 然后,您可以通过调用processWindowEvent()来调用该事件。 Here is a sample code that will create a JFrame, wait 5 seconds and close the JFrame without user interaction. 下面是一个示例代码,它将创建一个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();
    }

}

As you can see, the processWindowEvent() method causes the WindowClosed event to be fired where you have an oportunity to do some clean up code if you require before closing the application. 正如您所看到的,processWindowEvent()方法会导致触发WindowClosed事件,如果您在关闭应用程序之前需要执行某些清理代码,则会触发该事件。

Take a look at the Oracle Documentation . 查看Oracle文档

Starting from JDK 1.4 an Application terminates if: 从JDK 1.4开始,应用程序在以下情况下终止:

  • There are no displayable AWT or Swing components. 没有可显示的AWT或Swing组件。
  • There are no native events in the native event queue. 本机事件队列中没有本机事件。
  • There are no AWT events in java EventQueues. java EventQueues中没有AWT事件。

Cornercases: Cornercases:

The document states that some packages create displayable components without releasing them. 该文档指出某些包创建可显示的组件而不释放它们。 A program which calls Toolkit.getDefaultToolkit() won't terminate. 调用Toolkit.getDefaultToolkit()的程序不会终止。 is among others given as an example. 是作为一个例子给出的。

Also other Processes can keep AWT alive when they, for what ever reason, are sending events into the native event queue. 当其他原因将其发送到本机事件队列时,其他进程也可以使AWT保持活动状态。

Also I noticed that on some Systems it takes a coupple of seconds before the Application actually terminates. 另外我注意到在某些系统上,在应用程序实际终止之前需要几秒钟的时间。

我认为,这个想法就在这里WindowListener - 您可以在事物关闭之前添加任何您想要运行的代码

In response to other comments, DISPOSE_ON_CLOSE does not seem to properly exit the application - it only destroys the window, but the application will continue running. 为了响应其他注释,DISPOSE_ON_CLOSE似乎没有正确退出应用程序 - 它只会破坏窗口,但应用程序将继续运行。 If you want to terminate the application use EXIT_ON_CLOSE. 如果要终止应用程序,请使用EXIT_ON_CLOSE。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM