0

So my JProgressBar I have set up doesn't work the way I want it. So whenever I run the program it just goes from 0 to 100 instantly. I tried using a ProgressMonitor, a Task, and tried a SwingWorker but nothing I tried works.

Here is my program:

int max = 10;
for (int i = 0; i <= max; i++) {
        final int progress = (int)Math.round(
            100.0 * ((double)i / (double)max)
        );

        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ex) {
                    Logger.getLogger(BandListGenerator.class.getName()).log(Level.SEVERE, null, ex);
                }
                jProgressBar2.setValue(progress);
            }
        });
    }

@MadProgrammer Here is my attempt at making a swing worker and writing each name to the document and updating the progress bar. The program gets to around 86 percent and stops, never creating the finished document. The program creates a blank document. Here are the two methods first is the SwingWorker object I made:

public class GreenWorker extends SwingWorker<Object, Object> {
    @Override
    protected Object doInBackground() throws Exception {
        int max = greenList.size();
        XWPFParagraph tmpParagraph;
        XWPFRun tmpRun;
        FileInputStream file = 
                new FileInputStream(location + "GreenBandList.docx");
        gDocument = new XWPFDocument(OPCPackage.open(file));
        for (int i = 0; i < max; i++) {
            tmpParagraph = gDocument.getParagraphs().get(0);
            tmpRun = tmpParagraph.createRun();
            if (greenList.get(i).length() == 1) {
                    tmpRun.setBold(true);
                    tmpRun.setText(greenList.get(i));
                    tmpRun.setBold(false);
            } else {
                    tmpRun.setText(greenList.get(i));//Write the names to the Word Doc
            }
            int progress = Math.round(((float) i / max) * 100f);
            setProgress(progress);
        }
        return null;
  }        
}

And here is the code for the button that starts it and has my property change event.

private void GenerateGreenList() throws IOException, InterruptedException {
    //Need to fix the bug that removes the Letter Header in Yellow Band list
    //********************************************************************\\

    //Delete the old list and make a new one
    File templateFile = new File(location + "\\backup\\GreenTemplate.docx");
    FileUtils.deleteQuietly(new File(location + "GreenBandList.docx"));
    FileUtils.copyFile(templateFile, new File(location + 
            "GreenBandList.docx"));
    //Get the New Entries
    String[] entries = jTextPane3.getText().split("\n");
    for (String s : entries) {
        if (s != null) {
            greenList.add(s);
        }
    }
    //Resort the list
    Collections.sort(greenList);
    //Write the names to the document
    GreenWorker worker = new GreenWorker();
    worker.addPropertyChangeListener(new PropertyChangeListener() {
        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            if ("progress".equals(evt.getPropertyName())) {
                jProgressBar2.setValue((Integer) evt.getNewValue());
            }
        }
    });
    worker.execute();
    if (worker.isDone()) {
        try {
            gDocument.write(new FileOutputStream(new File(location + "GreenBandList.docx")));
            ////////////////////////////////////////////////////////////
        } catch (IOException ex) {
            Logger.getLogger(BandListGenerator.class.getName()).log(Level.SEVERE, null, ex);
        }
        JOptionPane.showMessageDialog(null, "Green Band List Created!");
        jProgressBar2.setValue(0);
    }
}

I used the property change listener from one of your other posts but I don't really understand what the one you wrote does or what it does in general?

ItsRainingHP
  • 139
  • 1
  • 4
  • 18

2 Answers2

5

Swing is a single threaded environment, that is, there is a single thread which is responsible for processing all the events that occur within the system, including repaint events. Should anything block this thread for any reason, it will prevent Swing from processing any new events, including, repaint events...

So all this ...

EventQueue.invokeLater(new Runnable() {
    @Override
    public void run() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException ex) {
            Logger.getLogger(BandListGenerator.class.getName()).log(Level.SEVERE, null, ex);        }
        jProgressBar2.setValue(progress);
    }
});

Is constantly pausing the Event Dispatching Thread, preventing it from actually doing any updates (or at least spacing them randomly)...

It's also likely that your outer loop is been run from within the context of the EDT, meaning that until it exists, nothing in the Event Queue will be processed. All your repaint requests will be consolidated down to a single paint request and voila, instant filled progress bar...

You really should use a SwingWorker - I know you said you tried one, but you've not shown any code as to your attempt in this regards, so it's difficult to know why it didn't work, however...

And forgive me if we haven't said this a few times before :P

Community
  • 1
  • 1
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • I movedte Thread.sleep to where you have it and I still have the same problem when the max gets large (which what I am going to use it for max will be quite big) the program just freezes. – ItsRainingHP Mar 01 '14 at 17:36
  • Did you look at the examples? Fro. The sounds of it, you're outer for loop is also executing from within the context of the EDT – MadProgrammer Mar 01 '14 at 20:07
  • I don't have any code for the SwingWorker because I don't quite understand how they work. I am looking at the code but I just don't understand it, the Worker Object what is the point of that when I have the same for loop concept before my progress bar. – ItsRainingHP Mar 08 '14 at 00:27
  • Basically what I want it I have a list that is being created with thousands of names and is being written to a Word document, all of this is done but I wanted to add a progress bar so the user knows that the program isn't freezing up. I know I didn't give code to work with but any help or point me in the right direction would be appreciated. – ItsRainingHP Mar 08 '14 at 00:28
  • This is exactly what SwingWorker is good for. In the doInBackground, you add the names, calling setProgress as you need to. Attach a PropertyChangeListerner to the worker and monitor for the progress property change event, which is all demonstrated in the linked examples – MadProgrammer Mar 08 '14 at 00:33
  • Thanks I will attempt to try and do this and post my code if it doesnt work here. – ItsRainingHP Mar 08 '14 at 00:39
  • I have attempted to make my own Swing Worker if you could have a look that would be great, the program works up until the progress hits 98 percent then never finishes, it gets all the names but doesn't write them to the document which is suppose to happen after the program is done which I override the Done() method in the Swing Worker which I forgot to post. – ItsRainingHP Mar 13 '14 at 17:29
  • Okay that was the most noob thing. My for loop needed to be <= not just – ItsRainingHP Mar 13 '14 at 18:35
1

You are evoking Thread.sleep inside the EvokeLater which means that it is running on another thread than your for loop. i.e., your for loop is completing instantaneously (well, however long it takes to loop from 1 to 100, which is almost instantaneously).

Move Thread.sleep outside of EvokeLater and it should work as you intend.

    int max = 10;
    for (int i = 0; i <= max; i++) {
        final int progress = (int)Math.round(
            100.0 * ((double)i / (double)max)
        );

        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                jProgressBar2.setValue(progress);
            }
        });
        try {
            Thread.sleep(1000);
        } catch (InterruptedException ex) {
            Logger.getLogger(BandListGenerator.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

Edit: agree with @MadProgrammer. It appears this is just an illustrative question, but you should make sure whatever you're trying to accomplish here you use a SwingWorker for.

ryvantage
  • 13,064
  • 15
  • 63
  • 112
  • I removed the Tread.sleep altogether and I still have the same problem when the max gets large (which what I am going to use it for max will be quite big) the program freezes. – ItsRainingHP Mar 01 '14 at 17:34