2013-02-26 33 views
0

我有一個使用JTabbedPane顯示多個不同選項卡的應用程序。其中一個標籤有一個線程運行以顯示其內容。當標籤不可見時,我已經實現了一個ComponentListener來停止線程。我可以看到當選中標籤時該線程變爲活動狀態,並在變得不可見時停止,非常符合預期。如何確保JTabbedPane的內容在JTabbedPane不再可見時收到ComponentEvent(componentHidden)

如果我關閉我的應用程序時沒有選擇線程選項卡,一切順利,應用程序關閉。如果關閉我的應用程序時,線程的選項卡可見,則選項卡不會收到ComponentEvent,因此該線程保持活動狀態,我需要手動終止應用程序(使用Eclipse中控制檯上的Terminate按鈕)。

我不想使用System.exit()方法關閉我的應用程序,而是停止所有線程並處理所有窗口。這就像一個魅力,除了這是一個線程的標籤。

我已經嘗試在處理我的窗口或removeAll()之前將JTabbedPane設置爲隱藏。沒有預期的結果。 removeAll()甚至有相反的結果。如果該選項卡未激活,它將收到一個ComponentEvent以指示它已變爲可見(componentShown)(實際上,所有選項卡將依次接收該事件,但沒有一個會獲得componentHidden)。

很顯然,當我通過文件菜單關閉窗口(通過其中的一些控件以及測試removeAll和setVisible(false)方法)以及窗口處理時因爲用戶在窗口角落點擊十字。

更新

我已經找到一種方法,使這似乎導致運行爲守護線程問題的建議線程。然而,這卻導致了意想不到的問題。啓動問題線程的類是我使用的JUNG軟件包中的VisRunner類。它包含一個方法「放鬆」,其中線程開始。

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

我本來期望此方法解決問題,但它只是增加了問題。當我現在啓動我的軟件時,它不會停止,即使有問題的選項卡甚至不可見(該選項卡已構建,但不可見)。在這種情況下,MyVisRunner的放鬆方法甚至沒有被調用;該線程不會在VisRunner類的其他任何地方初始化。註釋setRelaxer行將解決這個額外的問題(顯然保持原來的問題)。

更新2

我終於解決了這個問題。我沒有意識到,當我設置我自己的鬆弛器時,已經有一個鬆弛器正在運行。我已將代碼調整爲:

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

這樣既解決了附加問題,又解決了我原來的問題。

+0

顯然,解決這個問題的其他方法(ComponentEvent除外)也是受歡迎的。 – Stefan 2013-02-26 08:25:20

+0

你使用'Thread.setDaemon(true)'嗎? – oliholz 2013-02-26 08:27:50

+0

@oliholz,請參閱我對Thread.setDaemon()中MouseEvent的回答的反應。 – Stefan 2013-02-26 08:37:22

回答

1

你應該設置線程爲守護線程:

myThread.setDaemon(true); 

虛擬機將終止,如果沒有更多的跑動非守護線程


BTW,你可以在你的JFramewindowClosing事件添加WindowListener

+0

感謝您的提示,我不知道詳細信息。不幸的是,正在運行的線程是第三方庫中的一個線程,我不想修改它,儘管我可以讓它們將它們的線程更改爲非守護線程。 – Stefan 2013-02-26 08:33:33

+0

@Stefan好吧,如果你能得到該線程的引用,你可以自己改變它。 – Mordechai 2013-02-26 08:35:22

+0

不幸的是,圖書館(JUNG,[link](http://jung.sourceforge.net/))並沒有給我提供該線程的參考。 – Stefan 2013-02-26 08:42:36