3

I developed a Java application for creating and extracting an archive - like WinRAR. You can create several archives at the same time with multithreading. And recently, I wanted to add an information status during the archive creation in the form of JProgressBar in a new JFrame at every creation.

But my problem is generating information in the new status frame and the thread which create the archive. That's why I create the JFrame in the archive thread for updating the progress bar currently.

But like I could read it in a diverse information source and on your answers/comments, it's against Java Swing and performance; I can't create swing object elsewhere that the EDT.

But then, how should I solve my problem? How can I etablish communication between the writing of my archive and its status JFrame (with JProgressBar)?


EDIT:

I implemented SwingWorker to manage the GUI in my application. Now it's done, I have an other question:

With SwingWorker, how do I act on the background task with an event on status Frame's button? (Example: pause compression or stop it.)

Zoyd
  • 3,449
  • 1
  • 18
  • 27
damson
  • 2,635
  • 3
  • 21
  • 29

3 Answers3

5
  1. Put and display JProgressBar in a JDialog, and don't create a new Top-Level Container. Create that once and re-use that

  2. Long timed and heavy code would be better redirected to the BackGround Task

  3. You can move with progress in JProgressBar from a background task

    • only if GUI related code is done on EDT more Concurrency in Swing

    • and there are two correct ways to do it

      • by using SwingWorker

      • from Runnable#Thread but GUI rellated code must be wrapped into invokeLater()

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • I think I understood the concurency in swing performance. And I began to develope a new implementation with SwingUtilities(invokeLater / isEventDispatchThread) but the code is too heavy and the status GUI has some bug and freeze. I will try with SwingWorker. – damson Sep 21 '11 at 12:48
  • yes, right, check my posts marked with tag Table and SwingWorker, then you can choosing better and easiest option ... – mKorbel Sep 21 '11 at 13:11
  • ok. You know what ? I will implement SwingWorker in my application and if I have problems I will come back check you. – damson Sep 21 '11 at 13:28
  • again Runnable#Thread is easier for newbee mistakes or if whatewer gone wrong, – mKorbel Sep 21 '11 at 13:32
  • @mKorbel: +1 well done! And don't forget to invite me to stackoverflow careers if you gain the access ;) – Heisenbug Sep 21 '11 at 13:42
  • Yeah I know I haven't problem with Runnable#Thread. My problem is with swing performance – damson Sep 21 '11 at 13:46
  • @damson there aren't any differencies between these two methods about/with performance, btw this isn't Java issue (your topic) because three or more winrar running in same time to pretty kill SATA + Procesors on Win 32b OS – mKorbel Sep 21 '11 at 13:54
  • @Heisenbug no idea what .., can you give me link to your treasures :-) – mKorbel Sep 21 '11 at 13:58
5

As suggested by others, the best way is to use SwingWorker.

SwingWorker properties are listenable and listeners are always called in the EDT, thus, you could do something like:

public class ArchivingWorker extends SwingWorker<Void, Void> {
    JProgressBar progressBar = null;
    // Other members here...
    ...

    public ArchivingWorker(...) {
        // Any specific initialization here (in EDT)
        addPropertyChangeListener(new PropertyChangeListener() {
            @Override void propertyChange(PropertyChangeEvent e) {
                if (    "state".equals(e.getPropertyName())
                    &&  e.getNewValue() == StateValue.STARTED) {
                    // Background thread has just started, show a progress dialog here
                    progressBar = new JProgressBar();
                    ...
                }
                else if ("progress".equals(e.getPropertyName())) {
                    // Update progress bar here with e.getNewValue()
                    ...
                }
            }
        });
    }

    @Override protected Void doInBackground() {
        // Archiving process here and update progress from time to time
        setProgress(progress);

        return null;
    }

    @Override protected void done() {
        // Ensure that archiving process worked correctly (no exception)
        try {
            get();
        } catch (Exception e) {
            // Handle exception (user feedback or whatever)
        } finally {
            // Close progress dialog
            ...
        }
    }
}

Then you can use ArchivingWorker as you need it:

ArchivngWorker worker = new ArchivingWorker(...);
worker.execute();
jfpoilpret
  • 10,449
  • 2
  • 28
  • 32
  • I really forget to ask you, do you know something about http://stackoverflow.com/questions/7053865/cant-get-arrayindexoutofboundsexception-from-future-and-swingworker-if-thread – mKorbel Sep 21 '11 at 21:43
  • @mKorbel No but I will study. I suppose it talk about swing worker comportment. – damson Sep 21 '11 at 22:56
  • @jfpoilpret I agree but there is problem in your method doInBackground because the JprogressBar won't be update in the EDT. Else thanks for the rest, that give me some cloud for the conception . But I will work swingWorker because PropertyChangeListener is yet a few blur. – damson Sep 21 '11 at 22:56
  • @damson I don't think progress bar won't be updated in the EDT. `SwingWorker.setProgress()` trigger a `PropertyChangeEvent` for which all registered listeners will be called **in the EDT**, that's why I put the actual update of the progress bar in the `PropertyChangeListener`. If you are not sure, just print out `SwingUtilities.isEventDispatchThread()` from inside the PCL. – jfpoilpret Sep 22 '11 at 04:17
  • a ok I didn't see that it was SwingWorker method. It's just perfect for my case. thanks – damson Sep 22 '11 at 09:53
  • Thanks I succeed to integrate SwingWorker and that roxx but now I have a other problem. How act on the background task with event of status Frame's button ? I did it when I managed the different task manually but now with the swingWorker it's really particularly. Have you an idea of conception to do that ? – damson Sep 22 '11 at 20:29
  • @jfpoilpret I speak too fast. When I run my application on an old computer, they have some latence on GUI. The same than when I ran my appli without swingWorker in similar conditions. what do you think about it ? – damson Sep 23 '11 at 09:40
  • @Damson I think it would be preferable that you start a new question and you post the code you have written so far. It's hard to tell what could be wrong with such a little description. – jfpoilpret Sep 24 '11 at 05:59
1

The answer provided by @mKorbel is fine, but there really is no need to use another top-level container (e.g. a JDialog) to display the progress bar. Instead, you can use the Glass Pane of the JFrame instance.

Community
  • 1
  • 1
mrkhrts
  • 829
  • 7
  • 17
  • Thanks for answers. About Top-Level Container, I haven't any choice that use it because the JDialog take all focus of the aplication and the multi-task become useless with. (I don't know if i am understandable; tell me if i don't) – damson Sep 21 '11 at 13:02
  • @damson, Nope..that didn't make much sense at all. – mrkhrts Sep 21 '11 at 13:08