java-在EDT线程中调用Thread.sleep()时SwingWorker不运行

时间:2019-01-14 14:32:48

标签: java multithreading swing swingworker

我正在尝试创建一个程序来求解二次方程式并计算求解时间。我有JButton,当我单击它时,计算将开始。我的SwingWorker用于计时,它将每1秒更新一次时间。因为计算速度很快,所以我在JButton actionPerformed中调用Thread.sleep(),这样我就可以看到SwingWorker的计时时间,但是当我在EDT线程中调用Thread.sleep(3000)时,SwingWorker不起作用,但是等到等式求解完毕完成打印输出运行时间= 3s。我该如何解决这个问题,以便SwingWorker将每1秒更新一次时间,而不是仅打印3秒。

//SwingWorker for counting time
public class Worker extends SwingWorker<Integer, Long> {

   private JLabel label;

   public Worker(JLabel label) {
      this.label = label;
   }

   @Override
   protected Integer doInBackground() throws Exception {
      long i = System.currentTimeMillis();

      Timer SimpleTimer = new Timer(10, new ActionListener(){
         @Override
         public void actionPerformed(ActionEvent e) {

            publish(System.currentTimeMillis() - i);
         }
      });
      SimpleTimer.start();

      return  1; 
   }

    protected void process(List<Long> chunks) {

       for(long i : chunks) {
          label.setText("" + i);
       }
    }
}


//Solving quadratic function in JButton actionPerformed
private void solveActionPerformed(java.awt.event.ActionEvent evt) {                                      

    int a, b, c;
    double x1, x2;
    int i = 0;
    try {
        a = Integer.parseInt(inputA.getText());
        b = Integer.parseInt(inputB.getText());
        c = Integer.parseInt(inputC.getText());
    } catch (Exception e) {
        JOptionPane.showMessageDialog(this, "Re-enter.");
        return;
    }
    Worker worker = new Worker(clock);
    worker.execute();

            try {
    Thread.sleep(3000);
    } catch (Exception e) {

    }
    double delta = b * b - 4 * a * c;

    if(delta < 0) {
        result.setText(".");
    } else if(delta == 0) {
        result.setText("x1 = x2 = " + -b / 2 * a);
    } else {
        x1 = (-b + Math.sqrt(delta)) / (2 * a);
        x2 = (-b - Math.sqrt(delta)) / (2 * a);

        result.setText("<html>x1 = " + x1 +  "<br>x2 = " + x2 + "</html>");
    }
}                                  

我现在找到了解决方案,我将计时器和计算代码放在同一个线程类中:

public class NewThread implements Runnable {

   private JLabel label, result;
   private int a, b, c;

   public NewThread(JLabel label, int a, int b, int c, JLabel result) {
      this.label = label;
      this.a = a;
      this.b = b;
      this.c = c;
      this.result = result;
   }
   @Override
   public void run() {
      double x1, x2;  

      long i = System.currentTimeMillis();
      Timer timer = new Timer(10, new ActionListener(){
          @Override
          public void actionPerformed(ActionEvent e) {
             label.setText("Thoi gian tinh toan: " + (Math.round(System.currentTimeMillis() - i) / 1000) + " giay");
          }
      });

      timer.start();
      try {
         Thread.sleep(3000);
      } catch (Exception e) {

   }

    double delta = b * b - 4 * a * c;

    if(delta < 0) {
        result.setText("Phuong trinh vo nghiem.");
    } else if(delta == 0) {
        result.setText("Phuong trinh co nghiem kep x1 = x2 = " + -b / 2 * a);
    } else {
        x1 = (-b + Math.sqrt(delta)) / (2 * a);
        x2 = (-b - Math.sqrt(delta)) / (2 * a);

        result.setText("<html>Phuong co 2 nghiem.<br>x1 = " + x1 +  "<br>x2 = " + x2 + "</html>");
    }

    timer.stop();

}

1 个答案:

答案 0 :(得分:1)

  

我的SwingWorker用于计时,它将每1秒更新一次。

如果此工作人员的唯一责任是使用经过的时间来更新标签,那么Swing Timer是一个更好的选择。让SwingWorker doInBackground()实现进行繁重的计算,最后done()实现可能只是停止计时器并显示最终结果。

请勿在EDT中调用Thread.sleep(),因为它将冻结整个GUI事件处理,并且您可能只会看到最终结果而没有预期的定期更新。

更新

仅添加一个简单的代码段开头:

public void startCalculation() {

    Timer timer = new Timer(1000, new ActionListener() {

        AtomicInteger elapsedSeconds = new AtomicInteger();

        @Override
        public void actionPerformed(ActionEvent evt) {
            label.setText(String.format("Elapsed time: %d seconds", elapsedSeconds.incrementAndGet()));
       }
    });

    SwingWorker<Integer, Void> worker = new SwingWorker<Integer, Void>() {

        @Override
        protected Integer doInBackground() throws Exception {
            // do heavy stuff
            Thread.sleep(3000); // it is safe to "sleep" here because it's not executed in the EDT
            return 1;
        }

        @Override
        protected void done() {
            timer.stop();
            // update the GUI with the results here if it's required
        }
    };

    timer.start();
    worker.execute();
}