Java中的GUI多线程

时间:2018-02-12 09:35:16

标签: java multithreading swing user-interface

我正在为一个计算密集型程序的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();'计时器更新正常,但处理永远不会完成。我真的很感激帮助找出问题所在。

2 个答案:

答案 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...

它显示:

enter image description here

使用计时器的新方法

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();