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

java - SwingWorker doens't run when calling Thread.sleep() in EDT thread

我正在尝试创建一个程序来求解二次方程并计算求解时间。我有 JButton,当我点击它时,计算就会开始。我的 SwingWorker 是用来计时的,它会每 1 秒更新一次时间。因为计算很快,我在 JButton actionPerformed 中调用 Thread.sleep() 所以我可以看到 SwingWorker 计算时间,但是当我在 EDT 线程中调用 Thread.sleep(3000) 时,SwingWorker 不工作但等待方程求解完成打印出运行 time = 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>");
    }
}                                  

我现在找到了解决办法,我把定时器和计算代码放在同一个线程里class:

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

}

My SwingWorker is for counting time, it will update time every 1 second.

如果这个工作人员的唯一职责是用经过的时间更新标签,那么 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();
}