Як закрити програму Java Swing із коду


94

Який правильний спосіб припинити програму Swing із коду, і які є підводні камені?

Я намагався автоматично закрити свою програму після спрацьовування таймера. Але лише заклик dispose()до JFrameне зробив трюку - вікно зникло, але додаток не припинилося. Однак, закривши вікно кнопкою закриття, програма дійсно припиняє роботу. Що я повинен зробити?


Опублікуйте фрагмент коду вашого таймера.
Джеймс Шек,

Відповіді:


106

Вашу близьку дію за замовчуванням JFrame можна встановити на " DISPOSE_ON_CLOSE" замість " EXIT_ON_CLOSE(чому люди продовжують використовувати EXIT_ON_CLOSE - це поза мною).

Якщо у вас є нерозподілені вікна або недемонові потоки, ваша програма не припиняється. Це слід вважати помилкою (і вирішення проблеми за допомогою System.exit - дуже погана ідея).

Найпоширенішими винуватцями є java.util.Timer та спеціальна нитка, яку ви створили. Для обох слід встановити демон або їх потрібно явно вбити.

Якщо ви хочете перевірити наявність усіх активних кадрів, ви можете використовувати Frame.getFrames(). Якщо всі Windows / Frames утилізовані, використовуйте налагоджувач, щоб перевірити наявність усіх недемон-потоків, які все ще працюють.


У моєму випадку я з налагоджувачем виявив, що у мене Swingworker все ще активний. Я викликав його метод cancel (true) у програмі WindowClose Eventlistener, і програма завершується зараз. Дякую!
Hans-Peter Störr

Зверніть увагу, що, можливо, вам доведеться викликати dispose на кожному кадрі, і, як правило, цього "достатньо" (хоча встановлення типової дії наближення до EXIT_ON_CLOSE, мабуть, теж не погана ідея).
rogerdpack

Що робити, якщо у вас одне вікно відкриває інше, але не позбавляється, щоб ви могли використовувати його для backвікна? Якщо друге вікно потім закрито, і ви використовуєте DISPOSE_ON_CLOSEпрограму, не припиняється, оскільки перше вікно все ще "не розташоване" ... чи є спосіб вирішити це без використання DISPOSE_ON_CLOSE?
Svend Hansen

Перше вікно має додати себе як слухач до другого вікна та вжити відповідних заходів.
Джеймс Шек,

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

Сирий, але ефективний.


На жаль, це занадто грубо для мене. Я хочу, щоб події закриття вікна були оброблені для деяких дій очищення. Добре, я міг би виконати System.exit із SwingUtils.invokeLater, але я волів би зробити все правильно.
Hans-Peter Störr

5
System.exit (0) - це не просто сировина, це зло. Перевірте всі кадри, зателефонуйте утилізувати. Якщо це не вдається, запустіть налагоджувач і подивіться, які недемонові потоки ще живі.
Джеймс Шек,

Навіть у JDK було багато помилок, які залишають процес. Отже, +1 для виходу (), але ви можете відключити його у збірках налагодження.
Том Хоутін - таклін

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

Якщо я вас правильно розумію, ви хочете закрити програму, навіть якщо користувач не натиснув кнопку закрити. Вам потрібно буде зареєструвати WindowEvents, можливо, за допомогою addWindowListener () або enableEvents (), залежно від того, що більше відповідає вашим потребам.

Потім ви можете викликати подію за допомогою виклику 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).
Джеймс Шек,

2

Погляньте на документацію Oracle .

Починаючи з JDK 1.4, програма припиняється, якщо:

  • Немає відображуваних компонентів AWT або Swing.
  • У черзі власних подій немає власних подій.
  • У java EventQueues немає подій AWT.

Каркаси:

У документі зазначено, що деякі пакунки створюють компоненти, що відображаються, не випускаючи їх. Програма, яка викликає Toolkit.getDefaultToolkit (), не припиняється.наводиться серед інших як приклад.

Також інші Процеси можуть підтримувати AWT живим, коли вони з будь-якої причини надсилають події до власної черги подій.

Також я помітив, що на деяких системах проходить пару секунд, перш ніж програма дійсно завершиться.


0

Я думаю, ідея тут WindowListener - ви можете додати туди будь-який код, який ви хотіли б запустити до того, як річ вимкнеться


0

У відповідь на інші коментарі DISPOSE_ON_CLOSE, здається, не виходить належним чином із програми - він лише руйнує вікно, але програма продовжуватиме працювати. Якщо ви хочете припинити роботу програми, використовуйте EXIT_ON_CLOSE.


Ця відповідь свідчить про прямо протилежне відповіді Джеймса Шека. Який з них правильний? (коли я тестую за допомогою простої програми, обидва, здається, працюють ...)
АБО Mapper

Не пам’ятаю, як я тестував це зараз.
JSideris
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.