我正在为一个计算密集型程序的GUI工作,需要一段时间才能完成计算。我想在GUI上显示和更新处理时间,以供参考和作为用户指示程序正在运行。我创建了一个工作者来处理单独线程上的处理时间,如下所示:
public class Worker extends SwingWorker<String, String>{
JLabel label;
boolean run;
public Worker(JLabel label)
{
this.label = label;
this.run = true;
}
@Override
protected String doInBackground() throws Exception {
//This is what's called in the .execute method
long startTime = System.nanoTime();
while(run)
{
//This sends the results to the .process method
publish(String.valueOf(System.nanoTime() - startTime));
Thread.sleep(100);
}
return null;
}
public void stop()
{
run = false;
}
@Override
protected void process(List<String> item) {
double seconds = Long.parseLong(item.get(item.size()-1))/1000000000.0;
String secs = String.format("%.2f", seconds);
//This updates the UI
label.setText("Processing Time: " + secs + " secs");
label.repaint();
}
}
我将JLabel传递给Worker,它显示处理时间。以下代码创建Worker并执行执行主计算的runnable。
Worker worker = new Worker(jLabelProcessTime);
worker.execute();
//Check for results truncation
boolean truncate = !jCheckBoxTruncate.isSelected();
long startTime = System.nanoTime();
String[] args = {fileName};
//run solution and draw graph
SpeciesSelection specSel = new SpeciesSelection(args, truncate);
Thread t = new Thread(specSel);
t.start();
t.join();
ArrayList<Double> result = specSel.getResult();
drawGraph(result);
worker.stop();
我的问题是,在计算完成之前,处理时间不会在GUI上更新。我觉得我很亲密,因为没有't.join();'计时器更新正常,但处理永远不会完成。我真的很感激帮助找出问题所在。
答案 0 :(得分:1)
您的代码无法正常工作......
我为你创建了MVCE ...
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingWorker;
public class SwingWorkerTest extends JFrame {
public SwingWorkerTest() {
this.setLayout(new FlowLayout());
JButton button = new JButton("run");
JLabel label = new JLabel("time: -");
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Worker worker = new Worker(label);
worker.execute();
//Check for results truncation
// boolean truncate = !jCheckBoxTruncate.isSelected();
// long startTime = System.nanoTime();
// String[] args = {fileName};
//run solution and draw graph
// SpeciesSelection specSel = new SpeciesSelection(args, truncate);
// Thread t = new Thread(specSel);
// t.start();
// t.join();
// ArrayList<Double> result = specSel.getResult();
// drawGraph(result);
worker.stop();
System.out.println("button's actionPerformed finished");
}
});
this.getContentPane().add(button);
this.getContentPane().add(label);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
}
public static void main(String[] args) {
new SwingWorkerTest();
}
}
class Worker extends SwingWorker<String, String>{
JLabel label;
boolean run;
public Worker(JLabel label)
{
this.label = label;
this.run = true;
}
@Override
protected String doInBackground() throws Exception {
System.out.println("doInBackground..., run=" + run);
//This is what's called in the .execute method
long startTime = System.nanoTime();
// while(run)
// {
System.out.println("running...");
//This sends the results to the .process method
publish(String.valueOf(System.nanoTime() - startTime));
Thread.sleep(100);
// }
System.out.println("worker finished...");
return null;
}
public void stop()
{
// System.out.println("stop");
// run = false;
}
@Override
protected void process(List<String> item) {
System.out.println("processed");
double seconds = Long.parseLong(item.get(item.size()-1))/1000000000.0;
String secs = String.format("%.2f", seconds);
//This updates the UI
System.out.println("updating");
label.setText("Processing Time: " + secs + " secs");
// label.repaint();
}
}
简而言之,我发现,Worker.stop()
之前调用了doInBackground
,因此您的投放是错误的,因此永远不会调用publish
。
&#34;固定&#34;上面的代码打印(开始后我调整大小并点击了运行按钮):
button's actionPerformed finished
doInBackground..., run=true
running...
processed
updating
worker finished...
它显示:
使用计时器的新方法
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingWorker;
import javax.swing.SwingWorker.StateValue;
import javax.swing.Timer;
public class SwingWorkerTestNew extends JFrame {
int progress = 0;
public SwingWorkerTestNew() {
GridLayout layout = new GridLayout(2, 1);
JButton button = new JButton("run");
JLabel label = new JLabel("progress: -");
WorkerNew worker = new WorkerNew(label);
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
worker.execute();
System.out.println("button's actionPerformed finished");
}
});
this.getContentPane().setLayout(layout);
this.getContentPane().add(button);
this.getContentPane().add(label);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.pack();
this.setVisible(true);
Timer timer = new Timer(100, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (worker.getState() == StateValue.STARTED) {
++progress;
label.setText(Integer.toString(progress));
}
if (worker.getState() == StateValue.DONE) {
label.setText("done");
}
}
});
timer.start();
}
public static void main(String[] args) {
new SwingWorkerTestNew();
}
}
class WorkerNew extends SwingWorker<String, String> {
JLabel label;
public WorkerNew(JLabel label) {
this.label = label;
}
@Override
protected String doInBackground() throws Exception {
System.out.println("background");
Thread.sleep(2000);
System.out.println("done");
return null;
}
}
答案 1 :(得分:0)
我是以太复杂的方式解决这个问题。不需要SwingWorker。我解决了它如下:
//Check for results truncation
boolean truncate = !jCheckBoxTruncate.isSelected();
String[] args = {fileName};
//run solution and draw graph
SpeciesSelection specSel = new SpeciesSelection(args, truncate);
Thread t = new Thread(specSel);
t.start();
long startTime = System.nanoTime();
new Thread()
{
public void run() {
while(!specSel.isFinished())
{
double seconds = (System.nanoTime() - startTime)/1000000000.0;
String secs = String.format("%.2f", seconds);
jLabelProcessTime.setText("Processing Time: " + secs + " secs");
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(SpecSelGUI.class.getName()).log(Level.SEVERE, null, ex);
}
}
ArrayList<Double> result = specSel.getResult();
drawGraph(result);
}
}.start();