简体   繁体   English

再次调用线程时,Java线程更新jProgressBar不会更新

[英]Java thread updating jProgressBar does not update when thread is called again

I have two threads. 我有两个线程。 One is running the business logic from my BulkProcessor class which updates the BulkProcessor.getPercentComplete() variable: 一种是从我的BulkProcessor类运行业务逻辑,该类将更新BulkProcessor.getPercentComplete()变量:

public void run(){
   new SwingWorker<Void,Void>() {
      protected Void doInBackground() throws Exception {
         BulkProcessor.main(jTextField0.getText(), jTextField1.getText());
         return null;
      };
   }.execute();
}

My other thread is what updates the jProgressBar's value in my BulkGUI class: 我的另一个线程是什么来更新BulkGUI类中的jProgressBar的值:

public void update(){
   jProgressBar0.setStringPainted(true);
   jProgressBar0.repaint();
   new SwingWorker<Void,Integer>() {
   protected Void doInBackground() throws Exception {
      do
      {
          percentComplete = BulkProcessor.getPercentComplete();
          publish(percentComplete);
          Thread.sleep(100);
      } while(percentComplete < 100);
      return null;
      } 
      @Override
      protected
      void process(List<Integer> progress)
      {
          jProgressBar0.setValue(progress.get(0));
      }
}.execute();
}

I call the two threads when the Process button is clicked: 单击“处理”按钮时,我将调用这两个线程:

private void jButton0ActionActionPerformed(ActionEvent event) {
run();
update();
}

Running this the first time works exactly as expected. 第一次运行此程序完全符合预期。 However selecting the Process button a second time has no affect on the jProgressBar. 但是,第二次选择“处理”按钮对jProgressBar没有影响。 The local variable percentComplete in the update thread remains at 100, and does not update as it does the first run. 更新线程中的局部变量percentComplete保持为100,并且在第一次运行时不会更新。 I tested the percentComplete variable from the BulkProcessor class, and this variable does in fact update as expected. 我测试了BulkProcessor类中的percentComplete变量,该变量实际上确实按预期进行了更新。 So for some reason the thread is not fetching the update values using BulkProcessor.getPercentComplete() the second time the thread is called. 因此,由于某种原因,线程第二次调用该线程时,并未使用BulkProcessor.getPercentComplete()获取更新值。 Anybody have any insight on this? 有人对此有见识吗? Any help is much appreciated. 任何帮助深表感谢。

I'm guessing that your problem is likely because percentComplete is maximum the second time you press your button. 我猜您可能是因为第二次按下按钮时,percentComplete达到了最大值。 Suggestions: 建议:

  • reset percentComplete each time the code is run. 每次运行代码时重置percentComplete。
  • Avoid making Swing calls from within a background thread, including reading textfield text. 避免从后台线程内进行Swing调用,包括读取文本字段文本。
  • Rather do this in the SwingWorker's constructor, not in its doInBackground(...) method. 而是在SwingWorker的构造函数中执行此操作,而不是在其doInBackground(...)方法中执行此操作。
  • You appear to be making static field and/or method calls. 您似乎正在进行静态字段和/或方法调用。 If so, don't as this will bite you in the end, and instead create and pass valid references. 如果是这样,请不要这样做,因为这最终会咬住您,而是创建并传递有效的引用。
  • I'm guessing that to do this, you will want to create a new BulkProcessor object. 我猜想要这样做,您将需要创建一个新的BulkProcessor对象。
  • Calling run() and then update() as you're doing, getting two threads to run concurrently looks dangerous to me, a possible set up for a race condition. run()调用run()然后再调用update() ,让两个线程同时运行对我来说很危险,这可能是为了争用条件而设置的。

Edit 编辑

You should look into using a SwingWorker's progress property with a PropertyChangeListener. 您应该研究将SwingWorker的progress属性与PropertyChangeListener一起使用。 For instance: 例如:

public class FooGUI {

   // .....

   public void myRun() {
      String text1 = someTextField.getText();
      String text2 = otherTextField.getText();
      final BulkProcessor bulkProcessor = new BulkProcessor(text1, text2);
      bulkProcessor.addPropertyChangeListener(new PropertyChangeListener() {

         @Override
         public void propertyChange(PropertyChangeEvent pcEvt) {
            if (pcEvt.getPropertyName().equals("progress")) {
               int progress = bulkProcessor.getProgress();
               someProgressBar.setValue(progress);
            }
         }
      });
   }
}

class BulkProcessor extends SwingWorker<Void, Void> {
   private Random random = new Random(); // just for SSCCE sake
   private String text1;
   private String text2;

   public BulkProcessor(String text1, String text2) {
      this.text1 = text1;
      this.text2 = text2;
      // not sure what you do with these texts....
   }

   @Override
   protected Void doInBackground() throws Exception {
      int progress = 0;
      while (progress <= 100) {
         progress = random.nextInt(5); // just as a for instance
                                    // your code will do something else of course
         setProgress(progress);
         Thread.sleep(300);
      }
      return null;
   }

}

For example: 例如:

import java.awt.event.*;
import java.beans.*;
import java.util.Random;
import javax.swing.*;

@SuppressWarnings("serial")
public class Foo3 extends JPanel {
   private static final String DEFAULT_SPEED = "15";
   private JTextField speedTextField = new JTextField(DEFAULT_SPEED, 5);
   private JProgressBar someProgressBar = new JProgressBar();
   private RunAction runAction = new RunAction();
   private JButton runButton = new JButton(runAction);

   public Foo3() {
      speedTextField.setAction(runAction);

      add(new JLabel("Speed:"));
      add(speedTextField);
      add(someProgressBar);
      add(runButton);
   }

   public void myRun() {
      String speedText = speedTextField.getText();
      try {
         int speed = Integer.parseInt(speedText);
         final BulkProcessor bulkProcessor = new BulkProcessor(speed);
         bulkProcessor.addPropertyChangeListener(new PropertyChangeListener() {

            @Override
            public void propertyChange(PropertyChangeEvent pcEvt) {
               if (pcEvt.getPropertyName().equals("progress")) {
                  int progress = bulkProcessor.getProgress();
                  someProgressBar.setValue(progress);
               }
               if (pcEvt.getPropertyName().equals("state")) {
                  if (bulkProcessor.getState().equals(
                        SwingWorker.StateValue.DONE)) {
                     someProgressBar.setValue(0);
                     setGuiEnabled(true);
                  }
               }
            }
         });
         setGuiEnabled(false);
         bulkProcessor.execute();
      } catch (NumberFormatException e) {
         String text = "Speed of " + speedTextField.getText()
               + " is invalid. Please enter an integer";

         JOptionPane.showMessageDialog(this, text, "Invalid Speed Value",
               JOptionPane.ERROR_MESSAGE);
         speedTextField.setText(DEFAULT_SPEED);
      }
   }

   private class RunAction extends AbstractAction {
      public RunAction() {
         super("Run");
         putValue(MNEMONIC_KEY, KeyEvent.VK_R);
      }

      @Override
      public void actionPerformed(ActionEvent arg0) {
         myRun();
      }

   }

   private void setGuiEnabled(boolean enabled) {
      runButton.setEnabled(enabled);
      speedTextField.setEnabled(enabled);
   }

   private static void createAndShowGui() {
      Foo3 mainPanel = new Foo3();

      JFrame frame = new JFrame("Foo3");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

class BulkProcessor extends SwingWorker<Void, Void> {
   private Random random = new Random(); // just for SSCCE sake
   private int speed;

   public BulkProcessor(int speed) {
      this.speed = speed;
   }

   @Override
   protected Void doInBackground() throws Exception {
      int progress = 0;
      while (progress <= 100) {
         progress += random.nextInt(speed);
         setProgress(progress);
         Thread.sleep(300);
      }
      return null;
   }

}

So found that changing while(percentComplete < 100) to while(percentComplete <= 100) keeps the thread running permanently. 因此发现将while(percentComplete <100)更改为while(percentComplete <= 100)可以使线程永久运行。 This actually fixes the issue, might not be recommended however. 这实际上解决了问题,但是可能不建议这样做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM