Поток исполнения при использовании Swing - PullRequest
4 голосов
/ 05 февраля 2012

Я только начинаю разбираться с программированием GUI на Java.Вот тривиальная программа (из "Head First Java" О'Рейли), которая на первый взгляд кажется простой для понимания, но есть аспект, которому я не следую.

import javax.swing.*;

public class Test {
    public static void main(String[] args) {

    JFrame frame=new JFrame();
    JButton button = new JButton("click me");

    frame.getContentPane().add(button); 
        frame.setSize(300,300);
    frame.setVisible(true);
    }
}

Этопростая программа, когда она скомпилирована и запущена, откроет окно с кнопкой на ней.

Я не понимаю, что происходит с потоком выполнения.Когда я запускаю эту программу, запускается статический метод main класса Test, все команды в main() выполняются - так почему же процесс не завершается после появления окна?Почему я все еще сижу на чем-то похожем на бесконечный цикл?Что такое цикл?

Если я добавлю строку

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

, то я нахожу результат еще более непонятным.Теперь, конечно, программа завершается, когда я закрываю окно.Но опять же я не понимаю почему.Кадр будет в стеке, но я не вижу, где находится поток программы, и просто наличие чего-то в стеке недостаточно, чтобы поддерживать программу в живых, не так ли?Я упускаю что-то фундаментальное, что, насколько я вижу, не рассматривается в книге, которую я читаю.Я слегка удивлен этим - «Head first Java» до сих пор был очень хорош в том, чтобы указывать на тонкости и объяснять, что происходит на самом деле, но, похоже, не решает эту проблему (по крайней мере,не то, что я заметил).

Ответы [ 2 ]

4 голосов
/ 05 февраля 2012

почему процесс не завершается после появления окна?

Поскольку виртуальная машина Java завершается только после завершения всех потоков, не являющихся демонами. Хотя это и не очевидно, на самом деле в вашей программе есть два потока: основной поток и поток диспетчеризации событий , который выполняет все, что связано с компонентами Swing GUI. Поток диспетчеризации событий продолжается до тех пор, пока видны все компоненты графического интерфейса.

На самом деле программа, хотя она и может работать, неверна, потому что вы создаете и получаете доступ к компонентам Swing из основного потока. Вы должны выполнять всю работу с графическим интерфейсом в потоке диспетчеризации событий. То есть должно быть что-то вроде:

public static void main(String[] args) {

  EventQueue.invokeLater(new Runnable() {
    JFrame frame=new JFrame();
    JButton button = new JButton("click me");

    frame.getContentPane().add(button); 
    frame.setSize(300,300);
    frame.setVisible(true);
  });
}
1 голос
/ 05 февраля 2012

Процесс Java завершается, когда умирает последний недемонический поток.Обычно существует только один поток main.При отображении компонентов Swing запускаются дополнительные недемонические потоки для отправки событий и вывода графического интерфейса.Они заканчиваются, когда последний компонент верхнего уровня удаляется.В вашем примере поток main умирает после выхода из метода main.Вы можете просмотреть потоки с помощью отладчика или jvisualvm из инструментов JDK.

Остальная часть потока графического интерфейса пользователя управляется событиями.Когда вы, например, нажимаете кнопку закрытия кадра, генерируется событие и отправляется соответствующим слушателям в потоке диспетчеризации событий.

Установка JFrame.EXIT_ON_CLOSE в качестве операции закрытия по умолчанию аналогична добавлению прослушивателя событий по умолчанию в кадр.Довольно резкий, он просто отключает JVM независимо от остального состояния приложения.

...