无法从SwingWorker类获取JProgressBar进行更新 [英] Can't get JProgressBar to update from SwingWorker class

查看:49
本文介绍了无法从SwingWorker类获取JProgressBar进行更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

按下按钮时,扩展SwingWorker的另一个类开始起作用,并执行一系列可能很长的计算.我需要A类中的进度条,以根据B类中的变量来显示进度.

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

非常感谢您的帮助.

GUI类别:

  SignalSimulator signalSimulator =新的SignalSimulator(路径,numOfdataPoints,numOfLocalSpikes,numOfExpSpikes,noiseAmp,斜率,偏移量,rdbtnSineWave.isSelected());signalSimulator.addPropertyChangeListener(new PropertyChangeListener(){公共无效propertyChange(PropertyChangeEvent evt){字符串属性= evt.getPropertyName();if("progress" .equals(property)){int进度=(整数)evt.getNewValue();System.out.println("PropertChangeListener中的值为:" + progress);progressBar.setValue(progress);}}});signalSimulator.execute(); 

计算类:

 受保护的整数doInBackground()引发异常{如果(isSine){数据= generateSineWave(numOfDataPoints,noiseAmp,偏移量);数据= addAnomalies(数据,numOfPointOutliers,numOfExpSpikes);} 别的 {数据= generateLinearSignal(numOfDataPoints,noiseAmp,斜率,偏移量);数据= addAnomalies(数据,numOfPointOutliers,numOfExpSpikes);}writeLogFile(path,".txt",data);firePropertyChange("progress",1,1);setProgress((int)progress);发布(进度);System.out.println("doInBackground中的值为:" + progress);返回1;} 

编辑

原始问题仍然存在.由于某些原因,进度栏仍未更新,我肯定知道progressBar.setValue(progress)中的"progress"变量正在更新,但GUI中的进度条保持不变(固定为0)这是我的新代码:

GUI类:

  SignalSimulator signalSimulator =新的SignalSimulator(路径,numOfdataPoints,numOfLocalSpikes,numOfExpSpikes,noiseAmp,斜率,偏移量,rdbtnSineWave.isSelected());signalSimulator.addPropertyChangeListener(new PropertyChangeListener(){公共无效propertyChange(PropertyChangeEvent evt){字符串属性= evt.getPropertyName();if("progress" .equals(property)){int进度=(整数)evt.getNewValue();System.out.println("PropertChangeListener中的值为:" + progress);progressBar.setValue(progress);}}});signalSimulator.execute(); 

SwingWorker类:​​

  @Override受保护的Indoger doInBackground()引发异常{如果(isSine){数据= generateSineWave(numOfDataPoints,noiseAmp,偏移量);数据= addAnomalies(数据,numOfPointOutliers,numOfExpSpikes);}别的{数据= generateLinearSignal(numOfDataPoints,noiseAmp,斜率,偏移量);数据= addAnomalies(数据,numOfPointOutliers,numOfExpSpikes);}writeLogFile(path,".txt",data);返回1;}公共double [] generateSineWave(int numOfDataPoints,double noiseAmp,double offset){随机rnd =新的Random();double [] dataArray = new double [numOfDataPoints];为(int i = 0; i< numOfDataPoints; i ++){dataArray [i] = Math.sin(Math.toRadians(i))+ rnd.nextDouble()* noiseAmp + offset;进度=((double)i)/(double)numOfDataPoints * 100;//firePropertyChange("progress",1,1);setProgress((int)progress);//publish(progress);System.out.println("doInBackground中的值为:" + progress);}返回dataArray; 

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

 公共类ProgressBarTest实现PropertyChangeListener {私有JFrame框架;私人JButton btnRun;静态JProgressBar progressBar =新的JProgressBar(0,100);公共静态void main(String [] args){EventQueue.invokeLater(new Runnable(){公共无效run(){尝试 {//UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel);UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");ProgressBarTest窗口=新的ProgressBarTest();window.frame.setVisible(true);//SignalSimulator signalSimulator = new SignalSimulator();} catch(Exception e){e.printStackTrace();}}});}/***创建应用程序.*/公共ProgressBarTest(){初始化();}私人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 =新的JProgressBar();progressBar.setAlignmentX(Component.RIGHT_ALIGNMENT);progressBar.setBounds(0,252,444,20);progressBar.setStringPainted(true);frame.getContentPane().add(progressBar);JButton btnRun = new JButton(开始长期运行");btnRun.setBounds(167,214,159,31);frame.getContentPane().add(btnRun);btnRun.addActionListener(new ActionListener(){@Override公共无效actionPerformed(ActionEvent e){//TODO自动生成的方法存根长跑();}});}私人无效longRun(){LongRunner longRunner =新的LongRunner(100000);longRunner.addPropertyChangeListener(new PropertyChangeListener(){@Override公共无效propertyChange(PropertyChangeEvent evt){if("progress" .equals(evt.getPropertyName())){int progress =(int)evt.getNewValue();System.out.println("propertyChangeListener中的值:" + progress);progressBar.setValue(progress);}}});longRunner.execute();}@Override公共无效propertyChange(PropertyChangeEvent arg0){//TODO自动生成的方法存根}} 

还有SwingWorker:

  import javax.swing.SwingWorker;公共类LongRunner扩展了SwingWorker< Integer,Double> {int numOfPoints;双重进步;公共LongRunner(int numOfPoints){this.numOfPoints = numOfPoints;this.progress = 0;}私人空白runLong(int bigNum){for(int i = 0; i< bigNum; i ++){尝试 {Thread.sleep(100);} catch(InterruptedException e){//TODO自动生成的catch块e.printStackTrace();}进度=(((double)i * 100)/(double)bigNum);setProgress((int)progress);System.out.println("setProgress中的值:" + progress);}}@Override受保护的Indoger doInBackground()引发异常{runLong(numOfPoints);返回null;}} 

我在做什么错了?

解决方案

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

解决方案:请勿执行此操作.要使其运行时,请在您的工作程序上调用 execute().

如果您需要进一步的帮助,则首先需要帮助我们.您了解您已经发布了大量的代码,其中大多数代码与您的问题完全无关,并且肯定比您要求志愿者进行的工作还要多.请删除所有无关的无关代码,而创建并发布适当的 MCVE .


修改
您似乎也正在直接从EDT调用代码,该代码应留在此处的工作线程中:

  signalSimulator.execute();//******************************下面所有这些signalSimulator调用如果(rdbtnSineWave.isSelected()){数据= signalSimulator.generateSineWave(numOfdataPoints,noiseAmp,偏移量);数据= signalSimulator.addAnomalies(数据,numOfLocalSpikes,numOfExpSpikes);} else {//选择了线性信号数据= signalSimulator.generateLinearSignal(numOfdataPoints,noiseAmp,斜率,偏移量);数据= signalSimulator.addAnomalies(数据,numOfLocalSpikes,numOfExpSpikes);}signalSimulator.writeLogFile(path,".txt",data); 

您似乎还只创建了一个一个工作者对象,该对象不合适,因为您不能重复使用SwingWorker对象.

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

例如

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

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


编辑

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


修改
例如

  import java.awt.event.*;导入java.beans.PropertyChangeEvent;导入java.beans.PropertyChangeListener;导入java.util.Random;导入java.util.concurrent.ExecutionException;导入javax.swing.*;公共类ProgressExampleGui {私人JPanel mainPanel = new JPanel();私人JProgressBar progressBar = new JProgressBar();私人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 +%");}公共JComponent getMainComponent(){返回mainPanel;}public void setEnabled(已启用布尔值){pressMeBtn.setEnabled(启用);}私人静态void createAndShowGui(){ProgressExampleGui progExampleGui =新的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);}公共静态void main(String [] args){SwingUtilities.invokeLater(new Runnable(){公共无效run(){createAndShowGui();}});}}@SuppressWarnings(序列")类MyAction扩展AbstractAction {私人ProgressExampleGui gui;public MyAction(String name,int mnemonic,ProgressExampleGui gui){超级(名字);putValue(MNEMONIC_KEY,助记符);this.gui = gui;}@Override公共无效actionPerformed(ActionEvent e){AbstractButton source =(AbstractButton)e.getSource();gui.setProgress(0);source.setEnabled(false);MyWorker myWorker =新的MyWorker();myWorker.addPropertyChangeListener(new WorkerPropChngListener(gui));myWorker.execute();}}class WorkerPropChngListener类实现PropertyChangeListener {私人ProgressExampleGui gui;public WorkerPropChngListener(ProgressExampleGui gui){this.gui = gui;}@Override公共无效propertyChange(PropertyChangeEvent pcEvt){MyWorker myWorker =(MyWorker)pcEvt.getSource();if("progress" .equals(pcEvt.getPropertyName())){int进度=(((Integer)pcEvt.getNewValue()).intValue();gui.setProgress(progress);}如果(SwingWorker.StateValue.DONE.equals(pcEvt.getNewValue())){尝试 {myWorker.get();} catch(InterruptedException | ExecutionException e){e.printStackTrace();}gui.setEnabled(true);}}}类MyWorker扩展了SwingWorker< Void,Void>{私有静态最终int MAX_INCR = 8;私有静态最终长SLEEP_TIME = 200;私有静态最终int MAX_VALUE = 100;private int值= 0;private随机random = new Random();@Override受保护的Void doInBackground()引发异常{一会儿(值< MAX_VALUE){值+ = random.nextInt(MAX_INCR);值= Math.min(值,MAX_VALUE);Thread.sleep(SLEEP_TIME);setProgress(value);}返回null;}} 


修改
关于新代码,您遇到两个主要问题:

查看数据输出的结果:

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

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

接下来,您将重要变量隐藏起来,尤其是JProgressBar变量progressBar.在这里声明它并在类中对其进行初始化:

 公共类ProgressBarTest实现PropertyChangeListener {私有JFrame框架;私人JButton btnRun;静态JProgressBar progressBar = new JProgressBar(0,100); 

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

  private void initialize(){frame = new JFrame();//.....JProgressBar progressBar =新的JProgressBar();//.....frame.getContentPane().add(progressBar); 

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

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

  import java.awt.*;导入java.awt.event.*;导入java.beans.*;导入javax.swing.*;//!!无需实现PropertyChangeListener//!!公共类ProgressBarTest实现PropertyChangeListener {公共类ProgressBarTest2 {私有JFrame框架;私人JButton btnRun;//!!这不应该是静态的!//!!静态JProgressBar progressBar = new JProgressBar(0,100);私人JProgressBar progressBar =新的JProgressBar(0,100);//!!公共静态void main(String [] args){EventQueue.invokeLater(new Runnable(){公共无效run(){尝试 {UI管理器.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");ProgressBarTest2窗口=新的ProgressBarTest2();window.frame.setVisible(true);} catch(Exception e){e.printStackTrace();}}});}公共ProgressBarTest2(){初始化();}私人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 =新的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(开始长期运行");//!!没有阴影//!!btnRun.setBounds(167,214,159,31);JPanel面板=新的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公共无效actionPerformed(ActionEvent e){长跑();}});//!!frame.pack();frame.setLocationRelativeTo(null);frame.setVisible(true);}私人无效longRun(){//!!使用更现实的值,该值应显示侦听器的变化//!!LongRunner longRunner =新的LongRunner(100000);LongRunner2 longRunner =新的LongRunner2(10000);longRunner.addPropertyChangeListener(new PropertyChangeListener(){@Override公共无效propertyChange(PropertyChangeEvent evt){if("progress" .equals(evt.getPropertyName())){int progress =(int)evt.getNewValue();System.out.println("propertyChangeListener中的值:"+进度);progressBar.setValue(progress);}}});longRunner.execute();}//!!@Override//!!不需要//public void propertyChange(PropertyChangeEvent evt){//}}LongRunner2类扩展了SwingWorker< Integer,Double>.{私有静态最终长SLEEP_TIME = 15;//!!int numOfPoints;双重进步;公共LongRunner2(int numOfPoints){this.numOfPoints = numOfPoints;this.progress = 0;}私人空白runLong(int bigNum){for(int i = 0; i< bigNum; i ++){尝试 {//!!更快的周转,以便我们的bigNum可以改变//以一种现实的方式//!!Thread.sleep(100);Thread.sleep(SLEEP_TIME);//!!} catch(InterruptedException e){e.printStackTrace();}进度=(((double)i * 100)/(double)bigNum);setProgress((int)progress);//!!System.out.println("setProgress中的值:" +进度);//!!这会让我们放慢脚步}}@Override受保护的Indoger doInBackground()引发异常{runLong(numOfPoints);返回null;}} 

I have my main GUI thread which has a JprogressBar in it and is implementing ProprtyChangeListener.

When a button is pressed, a different class, which extends SwingWorker, kicks into action and performs a series of potentially long calculations. I need the progress bar in class A to present the progress according to a variable in Class B.

My code is below (could be a bit messy with all my failed tries...)

Would appreciate any help.

GUI CLASS:

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

Calculating class:

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;
}

EDIT

Original problem remains. For some reason the progress bar is still not updating, I know for sure that the "progress" variable in progressBar.setValue(progress) is updating yet the progress bar in the GUI remains unchanged (fixed at 0) here is my new code:

GUI Class:

    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 Class:

@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;           

EDIT Rewrote the whole thing without the extra (irrelevant) code. I guess I'm missing something basic here caus it still doesn't update the progress bar.

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

}

}

And the 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;
    }

}

What am I doing wrong here?

解决方案

You are calling doInBackground() directly from your code, something that is akin to calling run() directly in a runnable. This means that your code is not in fact running on a background thread, and so you are likely clobbering the event thread with long running code, preventing the Swing GUI, and your progress bar, from updating.

Solution: don't do this. Call execute() on your worker when you want it to run.

If you need further help, you're going to first have to help us. You understand that you have a ton of code posted, most of it completely unrelated to your problem at hand, and certainly more than you should ask volunteers to go through. Please get rid of all the extraneous unrelated code, and instead create and post a proper MCVE.


Edit
You also appear to be calling code directly from the EDT that should be left to your worker thread here:

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

You also appear to be creating only one worker object which is not proper since you can't re-use a SwingWorker object.

I suggest that you only create your SwingWorker object when it is needed, that you pass the information for what type of signal is needed into its constructor. This way the above methods can be called from the SwingWorker's doInBackground method where they belong.

e.g.,

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

Note that you have some other significant unrelated problems in the code you've posted, but they will have to be addressed at some other time, but they include use of null layout and setBounds, almost always a very bad idea.


Edit

Just to clarify once again, your main problem is that you're calling long-running code on the Swing event thread. Just because a method is located in your Worker class does not mean that calling it will automatically have it run on a background thread. The only way to guarantee this is to have the code called from within your doInBackground() method. Again, what you want to do is to create your new worker object when it is needed, for instance, inside of some ActionListener, and at the time of its creation, pass into it all the information that it will need to run. Then add your PropertyChangeListener, then .execute() your worker. Do this, and I'll bet your code will work much better.


Edit
For example

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;
   }
}


Edit
Regarding your new code, you've got two main problems:

Look at the results of your data output:

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

At the pace that this is going, your progress value will reach 1 and cause a visible change to the PropertyChangeListener and the JProgressBar when the next ice age is upon us. So first of all, change your sleep times, and change your big number to something more reasonable.

Next, you shadow important variables, notably your JProgressBar variable, progressBar. Here is where you declare it and initialize it in the class:

public class ProgressBarTest implements PropertyChangeListener {

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

As a side note, this variable should most definitely not be declared static, but that's not the cause of your current problem. The cause is that you in fact re-declare the same variable elsewhere in your initialize method, and then add this new object into your GUI:

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

  // .....

  JProgressBar progressBar = new JProgressBar();

  // .....

  frame.getContentPane().add(progressBar);

Please understand that this new progressBar variable references a completely different JProgressBar, and so if you advance the value of the object created in the class, your GUI will show nothing because it is displaying a completely different object. To solve this, **don't redeclare and initialize a new variable in the initialize method. Instead use the object created in the class.

Other problems with your code: you use null layout and setBounds a lot. This will show to all that you are a newbie Swing programmer, since it means that you like to create rigid programs that are extremely difficult to upgrade, and that may not look good on all systems. Instead use the layout managers. For instance, here's your code with a few changes, all noted by comments:

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;
   }
}

这篇关于无法从SwingWorker类获取JProgressBar进行更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆