Как я могу гарантировать, что содержимое JTabbedPane получило ComponentEvent (componentHidden), когда JTabbedPane больше не отображается

У меня есть приложение, которое использует JTabbedPane для отображения нескольких разных вкладок. На одной из этих вкладок запущен поток для отображения ее содержимого. Я уже реализовал ComponentListener для остановки потока, когда вкладка не видна. Я вижу, как поток становится активным, когда выбрана вкладка, и останавливается, когда становится невидимым, как и ожидалось.

Если я закрываю свое приложение, когда вкладка с потоком не выбрана, все идет хорошо, и приложение закрывается. Если я закрываю свое приложение, когда вкладка с потоком видна, вкладка не получает ComponentEvent, поэтому поток остается активным, и мне нужно закрыть приложение вручную (используя кнопку «Завершить» на консоли в Eclipse).

Я предпочитаю не использовать метод System.exit() для закрытия моего приложения, а скорее останавливать все потоки и удалять все окна. Это работает как шарм, за исключением этой вкладки с нитью.

Я уже пытался сделать JTabbedPane невидимым перед удалением моего окна или removeAll(). Ни то, ни другое не дало ожидаемого результата. Метод removeAll() даже дал противоположный результат. Если вкладка не была активной, она получит ComponentEvent, указывающий, что она стала видимой (componentShown) (фактически, все вкладки получат событие по очереди, но ни одна из них не получит componentHidden).

Очевидно, что поток должен быть остановлен как при закрытии окна через меню файла (над которым у меня есть некоторый контроль и где я протестировал методы removeAll и setVisible(false)), так и когда окно удаляется, потому что пользователь щелкает на кресте в углу окна.

Обновить

Я нашел способ заставить поток, который, кажется, вызывает проблему, работать как поток демона, как было предложено. Однако это привело к неожиданной проблеме. Класс, который запустил проблемный поток, был классом VisRunner из программного пакета JUNG, который я использую. Он содержит метод «расслабиться», в котором запускается поток.

  @Override
  public void relax() {
      // in case its running
      stop();
      stop = false;
      thread = new Thread(this);
      thread.setPriority(Thread.MIN_PRIORITY);
      thread.start();
 }

Я создал класс MyVisRunner:

import edu.uci.ics.jung.algorithms.layout.util.VisRunner;
import edu.uci.ics.jung.algorithms.util.IterativeContext;

public class MyVisRunner extends VisRunner {

   public MyVisRunner(final IterativeContext process) {
      super(process);
   }

   @Override
   public void relax() {
      // in case it's running
      Log.d("Relaxing");
      stop();
      stop = false;
      thread = new Thread(this);
      thread.setPriority(Thread.MIN_PRIORITY);
      thread.setDaemon(true);
      thread.start();
   }
}

Загружаю релаксатор так:

  visModel = new DefaultVisualizationModel<>(layout);
  visModel.setRelaxer(new MyVisRunner(layout));

Я ожидал, что это решит проблему, но это только усугубляет проблему. Когда я сейчас запускаю свой софт, он не останавливается, даже когда проблемная вкладка даже не видна (вкладка построена, но не видна). В этом случае метод Relax из MyVisRunner даже не вызывается; поток не инициализируется больше нигде в классе VisRunner. Комментирование строки setRelaxer решит эту дополнительную проблему (очевидно, сохранив исходную проблему).

Обновление 2

Я решил проблему наконец. Я не осознавал, что когда я устанавливал свой собственный релаксатор, он уже работал. Я изменил код на:

  visModel = new DefaultVisualizationModel<>(layout);
  visModel.getRelaxer().stop();
  visModel.setRelaxer(new MyVisRunner(layout));

Это решило как дополнительную проблему, так и мою первоначальную.


person Stefan    schedule 26.02.2013    source источник
comment
Очевидно, приветствуются и другие методы (кроме ComponentEvent) решения этой проблемы.   -  person Stefan    schedule 26.02.2013
comment
Вы использовали Thread.setDaemon(true) ?   -  person oliholz    schedule 26.02.2013
comment
@oliholz, посмотрите мою реакцию на ответ MouseEvent в Thread.setDaemon().   -  person Stefan    schedule 26.02.2013
comment
Какой тред еще жив? VisRunner? Вы можете остановить Relaxer вручную, myDefaultVisualizationModel.getRelaxer().stop()   -  person oliholz    schedule 26.02.2013
comment
Подозреваемый действительно VisRunner. Проблема с вашим подходом заключается в том, что главное окно (тот, что с JTabbedPane) ничего не знает о VisRunner. Вкладка, содержащая биты JUNG, уже вызывает функцию stop() релаксатора, когда видимость меняется на невидимую.   -  person Stefan    schedule 26.02.2013


Ответы (1)


Вы должны установить поток как поток демона:

myThread.setDaemon(true);

Виртуальная машина прекратит работу, если больше не будет запущенных потоков не демона.


Кстати, вы можете добавить WindowListener к JFrame для windowClosing событий.

person Mordechai    schedule 26.02.2013
comment
Спасибо за подсказку, не знал такой детали. К сожалению, запущенный поток является потоком в сторонней библиотеке, которую я бы предпочел не изменять, хотя я мог бы попросить их изменить свой поток на поток, не являющийся демоном. - person Stefan; 26.02.2013
comment
@Stefan хорошо, если вы можете получить ссылку на эту ветку, вы можете изменить ее самостоятельно. - person Mordechai; 26.02.2013
comment
к сожалению, библиотека (JUNG, ссылка) не дает мне ссылку на ветку. - person Stefan; 26.02.2013
comment
Теперь я смог обойти это, создав подкласс класса, который создает поток (к счастью, у класса был защищенный дескриптор потока, к которому я мог получить доступ). Тем не менее, программное обеспечение все еще работает, поэтому я сейчас ищу дополнительные потоки ;( - person Stefan; 26.02.2013
comment
Обновления в вопросе показывают, что заставило программное обеспечение продолжать работать независимо от моей адаптации. - person Stefan; 26.02.2013