[英]Java/Swing: the fast/slow UI binding problem
我需要一種方法將UI指標綁定到快速變化的值。
我有一個NumberCruncher
類,它在一個關鍵的非UI線程中進行大量繁重的處理,每秒循環數千次迭代,其中一些導致我關注的一組參數的更改。 (把它們想象成一個鍵值存儲)
我想在UI線程中以較慢的速率顯示那些; 10-20Hz就好了。 如何添加MVC樣式的通知,以便我的NumberCruncher
代碼不需要知道UI代碼/綁定?
這樣做的慣用方法是使用SwingWorker
類,並使用調用publish(V...)
來定期通知Event Dispatch線程,使其更新UI。
在以下來自Javadoc的示例中,數字運算在doInBackground()方法中的工作線程上進行,該方法在每次迭代時調用publish。 此調用導致在Event Dispatch線程上異步調用process(V ...)方法,允許它更新UI。 請注意,這可確保始終從Event Dispatch線程更新用戶交互。 另請注意,您可以選擇每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");
}
}
}
@Adamski建議的SwingWorker
更可取; 但是javax.swing.Timer
一個實例是一個方便的替代javax.swing.Timer
,因為“Timers的動作事件處理程序執行事件派發線程。”
根據您執行的眾多操作,讓NumberCrucher
修改/保持一個對象。 讓它在一個單獨的線程中運行。 在swing中使用與NumberCruncher修改的相同Object的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;
}
用戶界面:
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();
}
}
}
好像你可能想要采用“傾聽者”方法。 允許您的數字cruncher注冊偵聽器,然后每100-200個循環(可配置)(或在某些更改條件下),通知偵聽器他們應該知道有更新。
監聽器可以是另一個在其上有線程wait()的類,當它被通知時,它只是更新其內部變量,然后通知等待的線程。 然后,快速循環類可以快速更新外部值,而不用擔心訪問其快速變化的內部狀態。
wait()s的另一個線程也可以在一個定時器線程上有一個wait(),該線程設置為10-20HZ(可配置),在等待()同步類的下一次更新之前等待定時器。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.