코드에서 Java Swing 애플리케이션을 닫는 방법


94

코드에서 Swing 애플리케이션을 종료하는 적절한 방법은 무엇이며 함정은 무엇입니까?

타이머가 실행 된 후 자동으로 애플리케이션을 닫으려고했습니다. 그러나를 호출 dispose()하는 것만으로 JFrame는 트릭 이 발생 하지 않았습니다. 창이 사라졌지 만 응용 프로그램이 종료되지 않았습니다. 그러나 닫기 버튼으로 창을 닫으면 응용 프로그램이 종료됩니다. 어떻게해야합니까?


타이머 코드 스 니펫을 게시하세요.
— James Schek

답변:


106

JFrame 기본 닫기 작업을 DISPOSE_ON_CLOSE대신 " " 로 설정할 수 있습니다 EXIT_ON_CLOSE(사람들이 EXIT_ON_CLOSE를 계속 사용하는 이유는 저 밖에 없습니다).

처리되지 않은 창이나 데몬이 아닌 스레드가있는 경우 응용 프로그램이 종료되지 않습니다. 이것은 오류로 간주되어야합니다 (System.exit로 해결하는 것은 매우 나쁜 생각입니다).

가장 일반적인 원인은 java.util.Timer와 사용자가 만든 사용자 지정 스레드입니다. 둘 다 daemon으로 설정하거나 명시 적으로 종료해야합니다.

모든 활성 프레임을 확인하려면을 사용할 수 있습니다 Frame.getFrames(). 모든 Windows / 프레임이 삭제 된 경우 디버거를 사용하여 아직 실행중인 비 데몬 스레드를 확인합니다.


제 경우에는 디버거에서 Swingworker가 여전히 활성화되어 있음을 발견했습니다. WindowClose Eventlistener에서 cancel (true) 메서드를 호출하면 프로그램이 종료됩니다. 감사!
— Hans-Peter Störr

각 프레임에 대해 dispose를 호출해야 할 수 있으며 일반적으로 "충분합니다"(기본 닫기 작업을 EXIT_ON_CLOSE로 설정하는 것도 나쁘지 않을 수 있음).
— rogerdpack 2010

한 창에서 다른 창을 열었지만 자체적으로 배치하지 않아 back창에 사용할 수 있다면 어떨까요? 두 번째 창이 닫히고 DISPOSE_ON_CLOSE첫 번째 창이 여전히 "분할되지 않은"상태이기 때문에 프로그램이 종료되지 않는 경우 ... 사용 하지 않고 해결할 수있는 방법이 DISPOSE_ON_CLOSE있습니까?
— Svend Hansen

첫 번째 창은 두 번째 창에 대한 리스너로 자신을 추가하고 적절한 조치를 취해야합니다.
— James Schek

3
EXIT_ON_CLOSE를 사용하면 응용 프로그램이 강제로 종료됩니다. 프로그램이 종료되기 전에 조치를 취해야하는 경우 (예 : 작업 데이터 저장) 일반 스윙 이벤트 핸들러를 사용하는 대신 JVM 이벤트 핸들러를 활용해야합니다. 둘 다 "작동"하지만 EXIT_ON_CLOSE는 더 복잡한 앱에 문제를 일으킬 것입니다.
— James Schek 2013 년

34

EXIT_ON_CLOSE 인 것 같아요

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

실제로 앱을 떠나기 전에 몇 가지 정리 작업을 수행 System.exit(0)하는 Window Listener 를 작성할 수 있기 때문에 before 가 더 좋습니다 .

이 창 리스너를 사용하면 다음을 정의 할 수 있습니다.

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를 수행 할 수 있지만 적절한 작업을 수행하고 싶습니다.
— Hans-Peter Störr

5
System.exit (0)은 단지 조잡한 것이 아니라 사악합니다. 모든 프레임을 확인하고 dispose를 호출하십시오. 실패하면 디버거를 실행하고 데몬이 아닌 스레드가 아직 살아 있는지 확인하십시오.
— James Schek

프로세스를 떠나는 JDK 내에서도 많은 버그가 있습니다. 따라서 exit ()에 +1하지만 디버그 빌드에서 비활성화 할 수 있습니다.
— Tom Hawtin-tackline

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정확히 ... 클래스의 이름처럼 대문자로를
— 장 - 필립 펠렛

정말 고맙습니다! 이것은 가장 좋은 방법 중 하나입니다!
— rzaaeeff

9

다음 프로그램에는 System.exit ()를 명시 적으로 호출하지 않고 외부 스레드가없는 프로그램을 종료하는 코드가 포함되어 있습니다. 이 예제를 스레드 / 수신기 / 타이머 등을 사용하는 응용 프로그램에 적용하려면 WindowEvent가 actionPerformed () 내에서 수동으로 시작되기 전에 종료를 요청 (해당되는 경우 대기)하는 정리 코드 만 삽입하면됩니다.

표시된대로 정확하게 실행할 수있는 코드를 복사 / 붙여 넣기하려는 사람들을 위해 약간 못 생겼지 만 관련이없는 주요 방법이 끝에 포함됩니다.

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는 System.exit (0)이 아닌 dispose ()를 호출해야합니다.
— James Schek

2

Oracle 문서를 살펴보십시오 .

JDK 1.4부터 다음과 같은 경우 응용 프로그램이 종료됩니다.

  • 표시 가능한 AWT 또는 Swing 구성 요소가 없습니다.
  • 기본 이벤트 큐에는 기본 이벤트가 없습니다.
  • Java EventQueues에는 AWT 이벤트가 없습니다.

코너 케이스 :

문서에는 일부 패키지가 릴리스하지 않고 표시 가능한 구성 요소를 생성한다고 명시되어 있습니다. Toolkit.getDefaultToolkit ()을 호출하는 프로그램은 종료되지 않습니다. 예를 들면 다른 것들 중입니다.

또한 다른 프로세스는 어떤 이유로 든 이벤트를 네이티브 이벤트 큐로 보낼 때 AWT를 활성 상태로 유지할 수 있습니다.

또한 일부 시스템에서는 응용 프로그램이 실제로 종료되기까지 몇 초가 걸립니다.


0

아이디어는 여기에 WindowListener라고 생각합니다. 작업이 종료되기 전에 실행하려는 코드를 추가 할 수 있습니다.


0

다른 의견에 대한 응답으로 DISPOSE_ON_CLOSE는 응용 프로그램을 제대로 종료하지 않는 것 같습니다. 창만 파괴 할뿐 응용 프로그램은 계속 실행됩니다. 애플리케이션을 종료하려면 EXIT_ON_CLOSE를 사용하십시오.


이 응답은 James Schek의 대답과 정반대임을 시사합니다. 어느 것이 맞습니까? (간단한 응용 프로그램으로 테스트하면 둘 다 작동하는 것 같습니다 ...)
— 또는 Mapper

지금 어떻게 테스트했는지 기억 나지 않습니다.
— JSideris
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.