当前位置: 首页 > 面试题库 >

无法从SwingWorker类获取JProgressBar进行更新

司徒锐进
2023-03-14
问题内容

我有主GUI线程,其中有一个JprogressBar,并且正在实现ProprtyChangeListener。

当按下按钮时,扩展SwingWorker的其他类将开始执行并执行一系列可能很长的计算。我需要A类中的进度条以根据B类中的变量来呈现进度。

我的代码在下面(我所有失败的尝试都可能有点混乱…)

将不胜感激。

GUI类别:

SignalSimulator signalSimulator = new SignalSimulator(
                path, numOfdataPoints, numOfLocalSpikes,
                    numOfExpSpikes, noiseAmp, slope, offset,
                                    rdbtnSineWave.isSelected());       
signalSimulator.addPropertyChangeListener( new PropertyChangeListener() {
    public void propertyChange(PropertyChangeEvent evt) {
        String property = evt.getPropertyName();
        if ("progress".equals(property)) {
            int progress = (Integer) evt.getNewValue();
            System.out.println("value in PropertChangeListener is: " + progress);
            progressBar.setValue(progress);
        }
    }
});
signalSimulator.execute();

计算类:

protected Integer doInBackground() throws Exception {
    if (isSine){
        data = generateSineWave(numOfDataPoints, noiseAmp, offset);
        data = addAnomalies(data, numOfPointOutliers, numOfExpSpikes);
    } else {
        data = generateLinearSignal(numOfDataPoints, noiseAmp, slope, offset);
        data = addAnomalies(data, numOfPointOutliers, numOfExpSpikes);
    }
    writeLogFile(path, ".txt", data);
    firePropertyChange("progress", 1, 1);
    setProgress((int)progress);
    publish(progress);
    System.out.println("value in doInBackground is: " + progress);
    return 1;
}

编辑

原始问题仍然存在。出于某种原因,进度条仍然没有更新,我可以肯定ProgressBar.setValue(progress)中的“
progress”变量正在更新,但GUI中的进度条保持不变(固定为0),这是我的新代码:

GUI类:

    SignalSimulator signalSimulator = new SignalSimulator(path, numOfdataPoints, numOfLocalSpikes, numOfExpSpikes, noiseAmp, slope, offset, rdbtnSineWave.isSelected());       
    signalSimulator.addPropertyChangeListener( new PropertyChangeListener() {
      public void propertyChange(PropertyChangeEvent evt) {
        String property = evt.getPropertyName();

        if ("progress".equals(property)) {
            int progress = (Integer) evt.getNewValue();
             System.out.println("value in PropertChangeListener is: " + progress);
             progressBar.setValue(progress);

        }
      }
    });
    signalSimulator.execute();

SwingWorker类:

@Override
        protected Integer doInBackground() throws Exception {

            if (isSine){
                data = generateSineWave(numOfDataPoints, noiseAmp, offset);
                data = addAnomalies(data, numOfPointOutliers, numOfExpSpikes);
            }
            else{
                data = generateLinearSignal(numOfDataPoints, noiseAmp, slope, offset);
                data = addAnomalies(data, numOfPointOutliers, numOfExpSpikes);
            }

            writeLogFile(path, ".txt", data);

            return 1;}


public double[] generateSineWave(int numOfDataPoints, double noiseAmp, double offset){

            Random rnd = new Random();
            double[] dataArray = new double[numOfDataPoints];


            for (int i=0;i<numOfDataPoints;i++){

                dataArray[i] =  Math.sin(Math.toRadians(i))+rnd.nextDouble()*noiseAmp+offset;
                progress = ((double)i)/(double)numOfDataPoints*100;

                //firePropertyChange("progress", 1, 1);
                setProgress((int)progress);
                //publish(progress);
                System.out.println("value in doInBackground is: " + progress);
            }

            return dataArray;

编辑 重写整个内容,而无需额外的(不相关的)代码。我想我在这里缺少一些基本的东西,因为它仍然无法更新进度条。

public class ProgressBarTest implements PropertyChangeListener {


    private JFrame frame;
    private JButton btnRun;
    static JProgressBar progressBar = new JProgressBar(0,100);

public static void main(String[] args) {

        EventQueue.invokeLater(new Runnable()  {
            public void run() {
                try {
                    //UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"); 
                    UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); 
                    ProgressBarTest window = new ProgressBarTest();
                    window.frame.setVisible(true);
                    //SignalSimulator signalSimulator = new SignalSimulator();

                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        });
    }

/**
 * Create the application.
 */
public ProgressBarTest() {
    initialize();
}

private void initialize() {
    frame = new JFrame();
    frame.setBounds(100, 100, 450, 300);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().setLayout(null);
    frame.setResizable(false);

    JProgressBar progressBar = new JProgressBar();
    progressBar.setAlignmentX(Component.RIGHT_ALIGNMENT);
    progressBar.setBounds(0, 252, 444, 20);
    progressBar.setStringPainted(true);
    frame.getContentPane().add(progressBar);


    JButton btnRun = new JButton("Start Long Run");
    btnRun.setBounds(167, 214, 159, 31);
    frame.getContentPane().add(btnRun);
    btnRun.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {
            // TODO Auto-generated method stub
            longRun();
        }

    } );

}


private void longRun(){

    LongRunner longRunner = new LongRunner(100000);
    longRunner.addPropertyChangeListener(new PropertyChangeListener() {

        @Override
        public void propertyChange(PropertyChangeEvent evt) {

            if ("progress".equals(evt.getPropertyName())){
                int progress = (int) evt.getNewValue();
                System.out.println("Value in propertyChangeListener: "+progress);
                progressBar.setValue(progress);
            }
        }
    });
    longRunner.execute();
}
@Override
public void propertyChange(PropertyChangeEvent arg0) {
    // TODO Auto-generated method stub

}

}

和SwingWorker:

import javax.swing.SwingWorker;


public class LongRunner extends SwingWorker<Integer, Double>{

    int numOfPoints;
    double progress;

    public LongRunner(int numOfPoints) {

        this.numOfPoints = numOfPoints;
        this.progress = 0;
    }

    private void runLong(int bigNum){

        for (int i=0; i< bigNum; i++){

            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            progress =  (((double)i*100)/(double)bigNum);
            setProgress((int)progress);
            System.out.println("Value in setProgress: "+progress);

        }

    }
    @Override
    protected Integer doInBackground() throws Exception {

        runLong(numOfPoints);
        return null;
    }

}

我在这里做错了什么?


问题答案:

您是doInBackground()直接从代码中调用,类似于run()在可运行对象中直接调用。这意味着您的代码实际上并没有在后台线程上运行,因此您很可能会用长时间运行的代码破坏事件线程,从而导致Swing
GUI和进度条无法更新。

解决方案:不要这样做。execute()当您希望它运行时,请呼叫它的工人。

如果您需要进一步的帮助,则首先需要帮助我们。您了解您已经发布了大量的代码,其中大多数代码与您的问题完全无关,而且肯定比您要求志愿者通过的代码还要多。

编辑
您似乎也正在直接从EDT调用代码,这些代码应留在此处的工作线程中:

        signalSimulator.execute();

        // ************* all these signalSimulator calls below ***********
        if (rdbtnSineWave.isSelected()) {
           data = signalSimulator.generateSineWave(numOfdataPoints,
                 noiseAmp, offset);
           data = signalSimulator.addAnomalies(data, numOfLocalSpikes,
                 numOfExpSpikes);
        } else { // Linear signal is selected
           data = signalSimulator.generateLinearSignal(numOfdataPoints,
                 noiseAmp, slope, offset);
           data = signalSimulator.addAnomalies(data, numOfLocalSpikes,
                 numOfExpSpikes);
        }

        signalSimulator.writeLogFile(path, ".txt", data);

您似乎还只创建了 一个 不合适的工作程序对象,因为您不能重复使用SwingWorker对象。

我建议您仅在需要时创建SwingWorker对象,然后将需要哪种信号的信息传递到其构造函数中。这样,可以从SwingWorker所属的doInBackground方法中调用上述方法。

例如,

signalSimulator = SignalSimulator(rdbtnSineWave.isSelected())
signalSimulator.addPropertyChangeListener(...);
signalSimulator.execute();

请注意,您在已发布的代码中还存在其他一些不相关的重大问题,但是必须在其他时间解决,但它们包括使用null布局和setBounds,这几乎总是一个非常糟糕的主意。

编辑

再次澄清一下,您的主要问题是您正在Swing事件线程上调用长时间运行的代码。仅仅因为方法位于您的Worker类中并不意味着调用它会自动使它在后台线程上运行。保证这一点的唯一方法是在您的doInBackground()方法中调用代码。同样,您想要做的是在
需要时 创建新的辅助对象,例如,在某个ActionListener内部,并在创建该辅助对象
将所有需要运行的信息传递给该辅助对象。然后添加您的PropertyChangeListener,然后添加您.execute()的工作程序。这样做,我敢打赌您的代码会更好。

编辑
例如

import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Random;
import java.util.concurrent.ExecutionException;

import javax.swing.*;

public class ProgressExampleGui {
   private JPanel mainPanel = new JPanel();
   private JProgressBar progressBar = new JProgressBar();
   private JButton pressMeBtn  = new JButton(new MyAction("Press Me", KeyEvent.VK_P, this));

   public ProgressExampleGui() {
      progressBar.setStringPainted(true);
      progressBar.setString("");

      mainPanel.add(pressMeBtn);
      mainPanel.add(progressBar);
   }

   public void setProgress(int progress) {
      progressBar.setValue(progress);
      progressBar.setString(progress + "%");
   }

   public JComponent getMainComponent() {
      return mainPanel;
   }

   public void setEnabled(boolean enabled) {
      pressMeBtn.setEnabled(enabled);
   }

   private static void createAndShowGui() {
      ProgressExampleGui progExampleGui = new ProgressExampleGui();

      JFrame frame = new JFrame("Progress Example");
      frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      frame.getContentPane().add(progExampleGui.getMainComponent());
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

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

@SuppressWarnings("serial")
class MyAction extends AbstractAction {
   private ProgressExampleGui gui;

   public MyAction(String name, int mnemonic, ProgressExampleGui gui) {
      super(name);
      putValue(MNEMONIC_KEY, mnemonic);
      this.gui = gui;
   }

   @Override
   public void actionPerformed(ActionEvent e) {
      AbstractButton source = (AbstractButton) e.getSource();
      gui.setProgress(0);
      source.setEnabled(false);
      MyWorker myWorker = new MyWorker();
      myWorker.addPropertyChangeListener(new WorkerPropChngListener(gui));
      myWorker.execute();
   }
}

class WorkerPropChngListener implements PropertyChangeListener {

   private ProgressExampleGui gui;

   public WorkerPropChngListener(ProgressExampleGui gui) {
      this.gui = gui;
   }

   @Override
   public void propertyChange(PropertyChangeEvent pcEvt) {
      MyWorker myWorker = (MyWorker) pcEvt.getSource();
      if ("progress".equals(pcEvt.getPropertyName())) {
         int progress = ((Integer)pcEvt.getNewValue()).intValue();
         gui.setProgress(progress);
      }

      if (SwingWorker.StateValue.DONE.equals(pcEvt.getNewValue())) {
         try {
            myWorker.get();
         } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
         }
         gui.setEnabled(true);
      }
   }

}

class MyWorker extends SwingWorker<Void, Void> {
   private static final int MAX_INCR = 8;
   private static final long SLEEP_TIME = 200;
   private static final int MAX_VALUE = 100;
   private int value = 0;
   private Random random = new Random();

   @Override
   protected Void doInBackground() throws Exception {
      while (value < MAX_VALUE) {
         value += random.nextInt(MAX_INCR);
         value = Math.min(value, MAX_VALUE);
         Thread.sleep(SLEEP_TIME);
         setProgress(value);
      }
      return null;
   }
}

编辑
关于新代码,您有两个 主要 问题:

查看数据输出的结果:

Value in setProgress: 0.0
Value in setProgress: 0.001
Value in setProgress: 0.002
Value in setProgress: 0.003
Value in setProgress: 0.004
Value in setProgress: 0.005
Value in setProgress: 0.006
Value in setProgress: 0.007
Value in setProgress: 0.008
Value in setProgress: 0.009
Value in setProgress: 0.01
Value in setProgress: 0.011
Value in setProgress: 0.012
Value in setProgress: 0.013
Value in setProgress: 0.014
Value in setProgress: 0.015
Value in setProgress: 0.016
Value in setProgress: 0.017
Value in setProgress: 0.018
Value in setProgress: 0.019
Value in setProgress: 0.02
Value in setProgress: 0.021
Value in setProgress: 0.022
Value in setProgress: 0.023
Value in setProgress: 0.024
Value in setProgress: 0.025
Value in setProgress: 0.026
Value in setProgress: 0.027
Value in setProgress: 0.028
Value in setProgress: 0.029

按照这样的步伐,当下一个冰河时代到来时,您的进度值将达到1,并导致PropertyChangeListener和JProgressBar发生明显变化。因此,首先,改变您的睡眠时间,并将您的大量数字更改为更合理的数字。

接下来,对重要变量进行阴影处理,尤其是JProgressBar变量progressBar。在这里声明它并在类中对其进行初始化:

public class ProgressBarTest implements PropertyChangeListener {

   private JFrame frame;
   private JButton btnRun;
   static JProgressBar progressBar = new JProgressBar(0, 100);

附带说明一下,绝对不应声明此变量static,但这不是当前问题的原因。原因是实际上您在初始化方法的其他地方 重新声明
了相同的变量,然后将此新对象添加到GUI中:

private void initialize() {
  frame = new JFrame();

  // .....

  JProgressBar progressBar = new JProgressBar();

  // .....

  frame.getContentPane().add(progressBar);

请理解,这个新的progressBar变量引用了完全不同的JProgressBar,因此,如果您推进在类中创建的对象的值,则GUI将不显示任何内容,因为它显示的是完全不同的对象。为了解决这个问题,**不要在initialize方法中重新声明和初始化新变量。而是使用在类中创建的对象。

代码的其他问题:您经常使用null布局和setBounds。这将向所有人表明您是一名新手Swing程序员,因为这意味着您喜欢创建很难升级的刚性程序,并且在所有系统上看起来都不太好。而是使用布局管理器。例如,这是您的代码,其中有一些更改,所有更改都由注释指出:

import java.awt.*;
import java.awt.event.*;
import java.beans.*;

import javax.swing.*;

//!! no need to implement PropertyChangeListener
//!! public class ProgressBarTest implements PropertyChangeListener {
public class ProgressBarTest2 {
   private JFrame frame;
   private JButton btnRun;

   // !! this shouldn't be static!
   // !! static JProgressBar progressBar = new JProgressBar(0, 100);
   private JProgressBar progressBar = new JProgressBar(0, 100); // !!

   public static void main(String[] args) {
      EventQueue.invokeLater(new Runnable() {
         public void run() {
            try {
               UIManager
                     .setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
               ProgressBarTest2 window = new ProgressBarTest2();
               window.frame.setVisible(true);
            } catch (Exception e) {
               e.printStackTrace();
            }
         }
      });
   }

   public ProgressBarTest2() {
      initialize();
   }

   private void initialize() {
      frame = new JFrame();
      // !!frame.setBounds(100, 100, 450, 300);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      //!! frame.getContentPane().setLayout(null); //!! never use null layouts
      frame.setResizable(false);

      // !! don't create a shadowed variable
      // !! JProgressBar progressBar = new JProgressBar();

      progressBar.setAlignmentX(Component.RIGHT_ALIGNMENT);
      //!! progressBar.setBounds(0, 252, 444, 20);
      progressBar.setStringPainted(true);
      //!! frame.getContentPane().add(progressBar);
      frame.getContentPane().add(progressBar, BorderLayout.SOUTH);
      btnRun = new JButton("Start Long Run"); //!! no shadowing
      //!! btnRun.setBounds(167, 214, 159, 31);
      JPanel panel = new JPanel(); //!!
      panel.setPreferredSize(new Dimension(450, 300)); //!!
      panel.setLayout(new GridBagLayout()); //!!
      panel.add(btnRun); //!!
      frame.getContentPane().add(panel, BorderLayout.CENTER); //!!
      btnRun.addActionListener(new ActionListener() {
         @Override
         public void actionPerformed(ActionEvent e) {
            longRun();
         }
      });

      //!!
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   private void longRun() {
    //!! use a more realistic value, one that should show change in listener
      //!! LongRunner longRunner = new LongRunner(100000);
      LongRunner2 longRunner = new LongRunner2(10000);  
      longRunner.addPropertyChangeListener(new PropertyChangeListener() {
         @Override
         public void propertyChange(PropertyChangeEvent evt) {
            if ("progress".equals(evt.getPropertyName())) {
               int progress = (int) evt.getNewValue();
               System.out.println("Value in propertyChangeListener: "
                     + progress);
               progressBar.setValue(progress);
            }
         }
      });
      longRunner.execute();
   }

   // !! @Override // !! not needed
   // public void propertyChange(PropertyChangeEvent evt) {
   // }
}

class LongRunner2 extends SwingWorker<Integer, Double> {
   private static final long SLEEP_TIME = 15; // !!
   int numOfPoints;
   double progress;

   public LongRunner2(int numOfPoints) {
      this.numOfPoints = numOfPoints;
      this.progress = 0;
   }

   private void runLong(int bigNum) {
      for (int i = 0; i < bigNum; i++) {
         try {
            // !! quicker turn-over so that our bigNum can change
            // in a realistic way
            // !! Thread.sleep(100);
            Thread.sleep(SLEEP_TIME);// !!
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
         progress = (((double) i * 100) / (double) bigNum);
         setProgress((int) progress);
         // !! System.out.println("Value in setProgress: " + progress); //!! This will slow us down
      }
   }

   @Override
   protected Integer doInBackground() throws Exception {
      runLong(numOfPoints);
      return null;
   }
}


 类似资料:
  • 我需要将给定的任何图像转换为字节数组,以满足加密要求。我正在使用JProgressBar监控所选图像较大时的转换进度: 我定义了一个类,它使用,如下所示: 不幸的是,这个错误发生了! 我不知道我的代码出了什么问题!在写这段代码之前,我读了和,但我觉得我遗漏了什么!我能得到一个有用的提示吗。 谢谢:)

  • 问题内容: 我无法更新进度条…这是我的代码 进度栏状态仅在线程末尾更新。有人能帮我吗?? 问题答案: 谢谢大家 我这样解决了

  • 我将primefaces 3.3与JSF 2.1结合使用。在下面的代码中,我有一个primeFaces dataTable,其中包含从数据库中提取的数据行,该数据库通过页面左侧的树组件正确激活。dataTable显示和行为正确。我有一个名为“更新”的删除功能,它刷新我的数据表,并在数据库更新后反映我的更改。我的问题是f:facet(id=“header”)。该方面包含一个commandLink,它

  • 问题内容: 我正在尝试将JProgressBar添加到我的程序中,但不会更新!仅当原因为100%时,该值才会更改。这是我的方法。 更改进度栏的值位于上述方法的底部。 这就是我所谓的方法。 编辑:以上根本不是问题,问题之一是程序正在使用整数除法而不是十进制。 问题答案: 是一个整数,也是。因此发生的是小数被截断。你应该做什么,就像 这样做是确保将其除以具有十进制功能的数据类型,该数据类型将返回更具包

  • 我有一个以下格式的日期,我需要解析它,并转换成一个纪元时间。 关于我做错了什么有什么帮助吗?