繁体   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