4

我想這幾個小時..我有一個改變了我的用戶界面,這完全破壞了UI的一個JTextField線程。線程(讓我們稱之爲線程A)由ActionListener生成。 .setText()函數調用位於由線程A創建的額外線程(B)中。線程B是SwingUtilitis.invokeAll()和/或SwingUtilities.invokeAndWait()的參數。我嘗試了他們兩個。這裏有一些代碼使其更加清晰。的Java Swing線程改變UI - 併發症

這是我的ActionListener它創建線程A - 縮短當然:

public void actionPerformed(ActionEvent evt) { 
    Object source = evt.getSource(); 
    if (source == window.getBtn_Search()) { 
     Refresher refresh = new Refresher(); 
     refresh.start(); 
    } 
} 

這是我的線程A,以後把線程B到EDT隊列:

public class Refresher extends Thread implements Runnable { 

private int counter = 0; 
private UI window = null; 
private int defRefresh = 0; 

@Override 
public void run() { 
    while(true){ 
     -bazillion lines of code- 
       do { 
        try { 
         Refresher.sleep(1000); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
        if(window.canceled()) break; 
        UI.updateCounter(window.getLbl_Status(), (Configuration.getRefreshTime()-counter)); 
        counter++; 
       } while (counter <= Configuration.getRefreshTime()); 
      - more code- 
    } 
} 
} 

的UI。 updateCounter(...)會將線程B排隊到EDT中。

public static void updateCounter(final JLabel label, final int i) { 
    try { 
     SwingUtilities.invokeAndWait( 
      new Runnable() { 
       public void run() { 
        label.setText("Refreshing in: " + i + " seconds."); 
       } 
      } 
     ); 
    } catch (InvocationTargetException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (InterruptedException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
} 

現在,當最後一個函數被調用時,一切都會變得混亂起來。我嘗試了幾個小時不同的東西,但沒有成功。我也試過使用SwingWorker,但是一些或者什麼都沒有發生。

+0

而...什麼得到*「搞砸」*? – MadProgrammer

+0

我有一個包含多個較小JPanel的JPanel,它們包含一個圖標和多個JLabels。當函數被調用時,這些JLabel出現在不同的地方,一些完全消失。標籤window.getLbl_Status()與這些沒有任何關係,並且完全在其他地方。該圖標也改變了位置 – user1924422

+2

對標籤值的更改可能會影響其容器和其周圍容器的佈局 – MadProgrammer

回答

-1

當改變label的文字你至少應該打電話repaint()/revalidate()label上的最頂層容器,引發了重新佈局,invalidate()/revalidate()正確假設上的文字變化label電話。

+0

不,setText()將觸發revalidate()*和* repaint()。你自己沒有必要這樣做。請參閱http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/javax/swing/JLabel.java#JLabel.setText%28java.lang.String%29 – flup

+0

閱讀再次,我寫了:「假設標籤在文本更改時正確調用invalidate()/ revalidate()」,我從來沒有說過應該自己完成 – stryba

+0

重新驗證最上面的容器是沒有意義的,因爲標籤及其父面板已經已經通過重新驗證,並聲稱是有效的。如果標籤文本已經被重新繪製,重新繪製所有東西會實現什麼,儘管在尺寸錯誤的面板上?它會完全按照原樣重新繪製一切。你*可以*建議在標籤和祖父母上標明無效,然後在其祖父母上進行驗證。雖然即使如此,我會把它稱爲解決方法。 – flup

0

一般來說,標籤是不是在顯示該修改文本的非常好:其寬度的變化,並與它的佈局。

使用只讀的JTextField,也許在適當的風格變化,可能是一個更好的解決方案。

0

我想你已經創建的中間JPanel S可算作驗證根。因此,當您撥打setText()時,自動發生的revalidate()不會導致任何佈局更改高於父級JPanel的級別。

我不認爲你實際需要的面板,因爲JLabel可以同時包含圖標和文本。見the tutorial

所以我的建議是去掉面板或,如果他們服務於一個目的,確保isValidateRoot()在面板返回false。

0

invokeAndWait()嘗試允許發佈要在EDT上執行的Runnable任務,但會阻止當前線程並等待EDT完成執行任務。

但有潛在的僵局在invokeAndWait(),因爲是在創建一個線程相互依存的任何代碼。 如果調用代碼持有一些通過invokeAndWait()需要鎖定(顯式或隱式)代碼 的鎖定,那麼EDT代碼將等待EDT的非代碼釋放鎖定,這是因爲非EDT代碼 正在等待EDT代碼完成,並且應用程序將掛起。

正如我們在這裏看到的,修改由等待的非 EDT代碼傳遞的JLabel組件。

相反,我們可以使用

invokeLater()以創和排隊包含了Runnable特殊事件的 照顧。這個事件按照收到的順序在EDT上處理,就像任何其他事件一樣。 當它到達時,它通過運行Runnable的run()方法來調度。

SwingUtilities.invokeLater(new Runnable() { 
public void run() { 
label.setText("Refreshing in: " + i + " seconds."); 
} 
}); 

OR

isEventDispatchThread()如果目前正在對EDT執行調用代碼,返回true,否則爲false。

Runnable code= new Runnable() { 
       public void run() { 
        label.setText("Refreshing in: " + i + " seconds."); 
       } 
      } 
     ); 

if (SwingUtilities.isEventDispatchThread()) { 
code.run(); 
} else { 
SwingUtilities.invokeLater(code); 
}