1

I seem to have a problem with SwingWorker. I basically implemented the Java Example Code updating the UI from the propertyChange() method of my JFrame.

I also copied the sleep up to one second part in doInBackground. This leaves me with a good update rate of setProgress within my Worker.

However the propertyChange Event is fired only once about every 10sec. I know from the API that not every setProgress fires an event, and I'm ok with that, however it seems that this is kinda slow and too many events are lost.

When stepping through in a Debugger I get a better rate, ~once every 3 calls to setProgress

Any ideas why it is so slow?

Here are the parts of my Code:

public Void doInBackground() {
    Random random = new Random();
    setProgress(0);
    float getSize=0,gotSize=0;
    while (Sync.syncing) {
        //Sleep for up to one second.
        try {
             Thread.sleep(random.nextInt(1000));
        } catch (InterruptedException ignore) {
            ignore.printStackTrace();
        }
        try{
            getSize=Main.getSyncGet();
            gotSize=Main.getSyncGot();
            System.out.println("setProgress: "+(gotSize/getSize));
            setProgress((int)((gotSize/(getSize))*100));
        }catch(Exception e){
            Main.LOGGER.log(Level.WARNING,"Error setting progress",e);
        }
    }
    return null;
}

public void propertyChange(PropertyChangeEvent evt) {
        if ("progress" == evt.getPropertyName()) {
            jpb.setValue((Integer) evt.getNewValue());
        }
}

Kind Regards

Jens

JavaJens
  • 360
  • 1
  • 3
  • 14

3 Answers3

4

Your problem is quite possibly here:

System.out.println("setProgress: "+(gotSize/getSize));
setProgress((int)((gotSize/(getSize))*100));

Have you tested that the progress is actually being changed? A better println would be:

int value = (int)((gotSize/(getSize))*100);
System.out.println("setProgress: "+ value);
setProgress(value);

Now check to see if value is in fact changing.

Ooops, this is definitely wrong:

public void propertyChange(PropertyChangeEvent evt) {
        if ("progress" == evt.getPropertyName()) {
            jpb.setValue((Integer) evt.getNewValue());
        }
}

Don't compare Strings using ==. Use the equals(...) or the equalsIgnoreCase(...) method instead. Understand that == checks if the two objects are the same which is not what you're interested in. The methods on the other hand check if the two Strings have the same characters in the same order, and that's what matters here. So instead of

if (fu == "bar") {
  // do something
}

do,

if ("bar".equals(fu)) {
  // do something
}

or,

if ("bar".equalsIgnoreCase(fu)) {
  // do something
}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • I know that you can't compare strings using ==, however as I said this is an example from Oracle: http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ProgressBarDemoProject/src/components/ProgressBarDemo.java Furthermore I have checked for Progress. Progress is set, however the events are called too seldom – JavaJens Aug 30 '12 at 18:55
  • @JavaJens: more important than is progress set, can you tell us, does the progress value *change*? Again, if it doesn't change, the listeners won't be called. And it appears to me that the Oracle tutorial has a little bit of bad code in it. Wow! – Hovercraft Full Of Eels Aug 30 '12 at 19:05
  • Yes, I agree. It has bad code in it. The value does in fact not change as much as aspected. I tried to keep it below 100, meaning a few KB don't change the Bar. Plus I had some synchronisation issues going on. Can you give me a hint how to account for large change while staying below 100? I'm trying to monitor the progress of downloads. Thanks so far! – JavaJens Aug 30 '12 at 19:12
  • @JavaJens: I suppose you could use two JProgressBars, one for the overall download and one for smaller incremetns, but then again, who really cares about small increments? If you're waiting on 10 MB, a KB here and there shouldn't really be displayed. I would do my downloads in the SwingWorker and would update progress when a significant change has occurred. – Hovercraft Full Of Eels Aug 30 '12 at 19:17
  • I have the downloads on seperate threads, its just about notifying the user that sth. is happening :) I'll just ignore small changes from now on. Thank you! – JavaJens Aug 30 '12 at 19:21
  • @JavaJens: have a look at how TrashGod uses several SwingWorker threads in his answer [here](http://stackoverflow.com/questions/11366330/waiting-for-multiple-swingworkers/11372932#11372932). A great piece of code! – Hovercraft Full Of Eels Aug 30 '12 at 19:25
2
  1. read SwingWorker, there are described possible scenarios, including code examples

  2. setProgress(0); and setProgress((int)((gotSize/(getSize))*100)); must be called on EDT

  3. output from folows methods could be done on EDT during doInBackground()

    • process()

    • publish()

    • setProgress()

  4. most complex code example by @trashgod about PropertyChangeListener

  5. for better help sooner post an SSCCE

Community
  • 1
  • 1
mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • Given the link you have provided, leads to the ProgressBarDemo. Why should you need to call setProgress on the EDT? doInBackground is specifically not run on EDT, that is why setProgress leads to a PropertyChangeEvent, that is handled on EDT – JavaJens Aug 30 '12 at 18:57
0

You can try firing property changes manually:

setProgress(1);
firePropertyChange("progress", 0, 1);
mostar
  • 4,723
  • 2
  • 28
  • 45