2010-12-03 72 views
2

我有一個顯示文本的面板。我希望面板改變它的文本,然後在發生其他事情之前暫停應用程序。我正在使用Thread.sleep(1000)。但是,出於某種原因,應用程序在調用Thread.sleep之前未完成繪製面板(文本未被更改)。我也試過這個:Thread.sleep和重新繪製

board.invalidate(); 
board.setLeftMessage("Not"); 
board.setRightMessage("Here"); 
board.revalidate(); 
Date current = new Date(); 
long timeNow = current.getTime(); 
Date newDate = new Date(timeNow + 1000); 
while (current.before(newDate)) 
    current = new Date(); 

但是沒有運氣。任何人都有建議? 非常感謝。

+4

不要阻塞主線程。 – EboMike 2010-12-03 19:10:33

回答

8

您正在阻止AWT事件調度線程(EDT)。 EDT處理重繪和輸入事件,所以你的代碼不需要多線程(這實際上是不可能的)。在美國東部時間晚些時候使用javax.swing.Timer發送活動。 (不要混淆javax.swing.Timerjava.util.Timer!)

+0

哇 - 儘管如此,你說 - 「不要混淆」我仍然設法這樣做。應該使這個大膽;) – javamonkey79 2010-12-03 19:31:46

+1

@ javamonkey79我看到你的答案後,我實際上添加了這一點。 (Stack Overflow給出了一個五分鐘窗口,其中編輯沒有出現在歷史記錄中。) – 2010-12-03 20:18:20

3

看看javax.swing.Timer - 我認爲這是你需要做到的。編輯#1:Sun \ Oracle文檔實際上建議使用here的Swing定時器。

一般情況下,我們推薦使用Swing的 計時器,而不是通用 定時器用於GUI相關的任務,因爲 搖擺定時器都有着相同的, 預先存在的計時器線程,並自動 GUI相關任務 在事件派發線程上執行。 但是,如果您不想從 定時器觸摸GUI或需要執行冗長的 處理,您可能會使用通用定時器 。

編輯#2:它看起來像有一些很好的基本教程here

編輯#3:刪除了使用TimerTask的建議 - 在這種情況下,這將是一個壞主意。

+0

如果使用`TimerTask`,你將離開EDT,因此處於危險之中。 – 2010-12-03 19:11:16

+0

@湯姆 - 怎麼這樣?你能詳細說明嗎? – javamonkey79 2010-12-03 19:15:03

1

您不應該從主線程更新GUI組件。使用SwingUtilities.invokeLater安排在事件線程上的更新:

SwingUtilities.invokeLater(new Runnable() { 
    public void run() { 
    board.invalidate(); 
    board.setLeftMessage("Not"); 
    board.setRightMessage("Here"); 
    board.revalidate(); 
    } 
}; 
2

你的「長期運行的任務」需要在一個單獨的線程中運行。然後,當您想更新GUI時,您需要在事件調度線程(EDT)上運行代碼。然後你可以讓單獨的Thread進入睡眠狀態,這不會影響GUI的繪製。

你應該可以使用SwingWorker來做到這一點。有關更多信息,請參閱Concurrency的Swing教程部分。

如果您不喜歡使用SwingWorker,那麼您需要創建自己的Thread並在SwingUtilities.invokeLater()中包裝更新GUI的代碼。

1

Thread.sleep是一個長期運行的任務。當您在EDT中運行這樣的任務時,它會阻止執行的所有重新繪製請求。所有正在掛起並在睡眠階段發送的重新繪製請求都會排隊等待未來處理。

因此,當EDT走出sleep階段時,它會將所有重新繪製請求(如果已啓用默認屬性啓用了合併)合併爲一個執行的重新繪製。如果未啓用合併,則所有排隊的請求都會連續執行,而兩者之間沒有任何時間間隔。因此,UI似乎沒有更新。

要糾正這種情況,請使用在特定時間間隔後定期觸發的timer