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