簡體   English   中英

Java / Swing:快速/慢速UI綁定問題

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM