2012-10-16 35 views
1

我有一個小問題,現在我不得不在一個小的Java項目上工作。我試圖從Button事件處理程序運行一些線程;那麼最後一個線程必須更新UI上的TextArea。線程正在做計算工作。最重要的部分是讓UI炒作良好 - 我不想凍結UI,當然我想定期更新UI的TextArea從其他線程之一(而不是UI)。因此,這裏是我的代碼的一部分:Java:如何啓動一些異步操作並從其他線程更新ui?

裏面按鈕的事件處理程序,我開始這4個主題:

Thread generate = new CombinaMaker(); 
generate.run(); 

Thread forward = new TranslateForward(); 
forward.run(); 

Thread backward = new TranslateBackward(); 
backward.run(); 

Thread refresh = new Refresher(); 
refresh.run(); 

我想線程同時工作。刷新線程必須定期更新UI TextArea組件。

所以,這裏是我是如何從複習線程更新UI:

public static void updateProgress() 
{ 
    SwingUtilities.invokeLater(new Runnable() 
    { 
     public void run() 
     { 
      //HERE 
      //I have a loop that have to be looping at every 500 ms 
     } 
    } 
} 

我qustion是:我應該做的鏈接呢?我需要簡單而有效。這個循環讓我感到難過,因爲只要應用程序有效,它必須循​​環。可能這是凍結UI的原因?我知道我在某個地方犯了大錯,但在這一刻我無法找到它。可能是你可以建議我一些簡單的解決方案。最後一個想法 - 前4個主題:我想同時啓動它們,而不凍結我的UI。就這樣(從事件處理程序中像這樣開始......)正確的或者可能會更好?非常感謝朋友!

PS。如果通過我的'刷新'線程刷新用戶界面很難,我已經準備好了一個妥協的變體 - 通過他的擁有線程(UI線程)更新用戶界面。但在這種情況下,我可能必須使用一些'時間拍攝機制' - 避免凍結用戶界面。你在想什麼?

+0

你的問題是什麼,特別是你的代碼?使用其他線程或TimerTasks基本上是你必須做的,是的。 –

+0

更新進程中的循環 - 如何避免凍結UI?計時器任務? –

+0

這可能是個糟糕的建議,但我已經將視圖對象的引用傳遞給其他線程,然後讓這些線程直接將數據附加到視圖。適合小程序的作品。不確定我會在產品或任何東西中發佈它。 – aglassman

回答

3

主要問題是你的算法。取而代之的

SwingUtilities.invokeLater(new Runnable() { 
    public void run() { 
     //HERE 
     //I have a loop that have to be looping at every 500 ms 
    } 
} 

你應該有

// HERE 
// I have a loop that have to be looping at every 500 ms 
// and when something must be updated in the GUI: 
SwingUtilities.invokeLater(new Runnable() { 
    public void run() { 
     // update the GUI as fast as possible 
    } 
}); 

while (true) { 
    Thread.sleep(500L); 
    String update = getUpdate(); 
    SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
      textArea.append(update); 
     } 
    }); 
} 

了Runnable傳遞給SwingUtilities.invokeLater()在事件調度線程中執行。它不能執行長時間運行的任務。無休止地循環是一項非常漫長的任務。

1

SwingUtilities.invokeLater沒有被設計用來調用長時間運行的線程。 您的問題的一個解決方案可能是this one

您也可以嘗試反轉你的循環和SwingUtilities.invokeLater調用的嵌套,但這樣做的可行性取決於你的代碼的其餘部分

do { 
    // Sleep and other stuff 
    SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
     // Update UI 
     } 
    }); 
} while(...); 
2

你不想循環的可運行你傳遞給invokeAndDoLater。看到這個例子:http://www.javamex.com/tutorials/threads/invokelater.shtml

+0

給出的鏈接雖然會成功地隱藏OP,但沒有提及可運行內部的循環。 ASAIK在runnable中有一個循環並沒有什麼錯,就係統而言,這只是另一個線程。唯一的問題是它與事件分派是同步的,所以如果循環沒有退出或者yield(),那麼它將阻塞事件分派。 –

+0

許多swing對象不同步,因此重要的是不要從其他線程更新它們。 InvokeAndDoLater的目的是在AWT更新線程上獲取您的更改(並因此避免使用AWT線程的競爭條件)。你永遠不想在該線程上執行繁重的操作(例如循環),因爲UI將凍結,直到操作完成。所以從技術上講,你沒有什麼可以阻止你,但如果你想要一個響應式的用戶界面,這是一個非常糟糕的主意。 – Gus

1

我不想凍結當然UI和

豎起大拇指不希望凍結UI。不幸的是,

我想定期

更新從其他線程的一個用戶界面的TextArea不是一個選項。更新Swing組件必須在UI線程(Event Dispatch Thread)上完成。幸運的是,Swing有一個定期更新UI的內置類:javax.swing.Timer類。 Timer在後臺運行,並在事件調度線程上執行,因此它非常適合執行此任務。