我需要一種將UI指示符綁定到快速更改值的方法。Java/Swing:快速/慢速UI綁定問題
我有一個類NumberCruncher
,它在一個關鍵的非UI線程中執行一堆繁重的處理,每秒循環數千次,其中一些會導致我關心的一組參數發生變化。 (將它們視爲鍵值存儲)
我想在UI線程中以較慢的速率顯示它們; 10-20Hz會很好。我如何添加MVC風格的通知,以便我的NumberCruncher
代碼不需要知道UI代碼/綁定?
我需要一種將UI指示符綁定到快速更改值的方法。Java/Swing:快速/慢速UI綁定問題
我有一個類NumberCruncher
,它在一個關鍵的非UI線程中執行一堆繁重的處理,每秒循環數千次,其中一些會導致我關心的一組參數發生變化。 (將它們視爲鍵值存儲)
我想在UI線程中以較慢的速率顯示它們; 10-20Hz會很好。我如何添加MVC風格的通知,以便我的NumberCruncher
代碼不需要知道UI代碼/綁定?
執行此操作的習慣方法是使用SwingWorker
類,並使用對publish(V...)
的調用來定期通知Event Dispatch線程,以使其更新UI。
在以下Javadoc示例中,數字運算髮生在doInBackground()方法中的工作線程上,該方法在每次迭代時調用發佈。此調用使事件調度線程上的進程(V ...)方法異步調用,從而允許它更新UI。請注意,這可確保用戶交互界面始終從事件調度線程更新爲。另請注意,您可以選擇每N次迭代調用一次發佈,以降低用戶界面的更新頻率。
實施例從Javadoc中
class PrimeNumbersTask extends
SwingWorker<List<Integer>, Integer> {
PrimeNumbersTask(JTextArea textArea, int numbersToFind) {
//initialize
}
@Override
public List<Integer> doInBackground() {
while (! enough && ! isCancelled()) {
number = nextPrimeNumber();
publish(number);
setProgress(100 * numbers.size()/numbersToFind);
}
}
return numbers;
}
@Override
protected void process(List<Integer> chunks) {
for (int number : chunks) {
textArea.append(number + "\n");
}
}
}
有一個對象,您的NumberCrucher
根據您所做的衆多操作修改/保持更改。讓它運行在一個單獨的線程中。使用與NumberCruncher修改相同的Object的swing中有一個UI。這個線程只會在指定的時間段讀取值,所以它不應該是線程死鎖的問題。
NumberCruncher
public class NumberCruncher implements Runnable{
CommonObject commonObj;
public NumberCruncher(CommonObject commonObj){
this.commonObj = commonObj;
}
public void run() {
for(;;){
commonObj.freqChangeVal = Math.random();
}
}
}
CommonObject:
public class CommonObject {
public double freqChangeVal;
}
UI:
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class UI extends JFrame implements Runnable{
private CommonObject commonObj = new CommonObject();
JLabel label ;
public static void main(String args[]){
UI ui = new UI();
ui.begin();
Thread t2 = new Thread(ui);
t2.start();
}
private void begin(){
JPanel panel = new JPanel();
label = new JLabel("Test");
panel.add(label);
Thread thread = new Thread(new NumberCruncher(commonObj));
thread.start();
this.add(panel);
this.setSize(200,200);
this.setVisible(true);
}
public void run() {
for(;;){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
label.setText(commonObj.freqChangeVal+"");
this.repaint();
}
}
}
-1:a)CommonObject的freqChangeVal字段不是易失性的,因此一個線程的更改可能在另一個線程上不可見。 b)UI run()方法在Event Dispatch線程上沒有被調用,這意味着JLabel正在被另一個線程修改(這不應該發生)。 c)這是重新發明車輪;更合適的機制是使用帶調用的SwingWorker來發布/處理,以便在Event Dispatch Thread上定期通知GUI。 – Adamski 2010-03-30 20:59:41
@Adamski:感謝您花時間在我的程序中指出問題。 – bragboy 2010-03-31 09:12:44
沒問題 - 你說得對,使用已經提供的任何類,併發是非常困難的。 – Adamski 2010-03-31 11:00:34
好像你MI ght想採取「聽衆」的方法。允許你的數字計算器註冊監聽器,然後每隔100-200個循環(可配置)(或在某種變化條件下),通知監聽器他們應該知道更新。
監聽器可以是另一個具有線程wait()的類,當它被通知時,它只是更新其內部變量,然後通知等待的線程。然後快速循環類可以快速更新外部值,而不用擔心訪問其快速更改的內部狀態。
wait()的另一個線程也可以在定時器線程上有一個wait(),該線程設置爲10-20HZ(可配置),以便在等待來自同步的下一次更新類。
SwingWorker
,通過@Adamski建議的,是優選的;但javax.swing.Timer
的一個實例是一個方便的替代方案,因爲「定時器的動作事件處理程序執行事件分派線程。」
所以publish()和process()處理隊列?有趣.... – 2010-03-30 21:44:33