1

According to the SwingWorker Javadoc:

When writing a multi-threaded application using Swing, there are two constraints to keep in mind:

  • Time-consuming tasks should not be run on the Event Dispatch Thread. Otherwise the application becomes unresponsive.
  • Swing components should be accessed on the Event Dispatch Thread only.

Thus, when using SwingWorker, we must access Swing Components only in done() and process() methods.

So, I created a sample application which loads 3000 rows from database in chunks, each chunk with 50 rows and display it.

SwingWorker<List<Person>, Person> worker = 
   new SwingWorker<List<Person>, Person>() {

      protected List<Person> doInBackground() {
         List<Person> data = new ArrayList<>();
         while (hasMoreData()) {
            List<Person> chunk = loadFiftyRows();
            data.addAll(chunk);
            publish(chunk);
         }
         return data;
      }

      protected void process(List<Person> chunks) {
         for (Person person : chunks) {
            container.add(createPanelFor(person));
         }
         container.revalidate();
         container.repaint();
      }

   };
worker.execute();

As, All swing access must be done on EDT, I am creating new JPanel instances for each person in the process() method. But, still the application is quite heavy on start up. It freezes and response to the events while the data is loading, is quite late.

Although, we are publishing 50 rows at a time, the chunk size gets bigger when process() method is invoked on EDT, sometimes 1000 rows. I think this is the cause of the delay, creating 1000 instances of JPanel on EDT!

I feel, creating 1000 new instances of JPanel is also a quite heavy task, to be performed on EDT. So, can't we create these JPanel instances in doInBackground() method, store it in a collection and then add those already created JPanel instances to the container in the process method?

But, it will contradict the statement, "Swing components should be accessed on the Event Dispatch Thread only"!

Does this statement mean, Existing Swing Components that have been added to the Swing Component Hierarchy and not newly created Swing Components?

Akshat
  • 720
  • 9
  • 24
  • 1
    3000 panels is quite a large number. You should probably use a JTable, or at least use the same strategy as the one it uses: use a single renderer component that is used to paint all the "cells" of a unique component displaying all the persons. Do you really need 3000 persons displayed at once. Couldn't you just display hundred people, and use a search form or pagination? – JB Nizet Apr 11 '15 at 16:21
  • 1
    @JBNizet makes an important point, as suggested [here](http://stackoverflow.com/q/25526833/230513). – trashgod Apr 11 '15 at 16:23
  • But we can create complex UI components using `JPanel`. And, listeners can be easily added to each individual panel! I am not able to see, how can we implement such GUI using JTable. Like this UI, in which each panel has a star button. https://cms-images.idgesg.net/images/article/2014/10/new-gmail-app-android-lollipop-inbox-100527809-large.idge.jpg I can implement it easily using `JPanel` but can't able to figure out using JTable or single renderer strategy. – Akshat Apr 11 '15 at 16:34
  • @JBNizet Actually, I want to follow modern design guidelines. And, I think, pagination is outdated. However, I thought about infinite-scroll technique which would load only some rows and add them to existing container. What do you think about it? – Akshat Apr 11 '15 at 16:38
  • 1
    It's another form of pagination. Why not. – JB Nizet Apr 11 '15 at 16:42
  • @JBNizet But can we create Swing Components on a different thread except EDT & add them on EDT? That's my question! Because, after GUI has loaded and populated 3000 panels, it runs smooth. It freezes only when creating thousands of instances on startup. – Akshat Apr 11 '15 at 16:46
  • 1
    That would violate the Swing concurrency rules. It might work fine, or not. It might work fine sometimes, and sometimes not. It might work fine somewhere, or with a given Java version, but not somewhere else, or on another Java version. Maybe all you need is a "loading..." dialog. – JB Nizet Apr 11 '15 at 16:50

1 Answers1

1

Swing Threading Policy states:

In general Swing is not thread safe. All Swing components and related classes, unless otherwise documented, must be accessed on the event dispatching thread. Typical Swing applications do processing in response to an event generated from a user gesture. For example, clicking on a JButton notifies all ActionListeners added to the JButton. As all events generated from a user gesture are dispatched on the event dispatching thread, most developers are not impacted by the restriction.

Where the impact lies, however, is in constructing and showing a Swing application. Calls to an application's main method, or methods in Applet, are not invoked on the event dispatching thread. As such, care must be taken to transfer control to the event dispatching thread when constructing and showing an application or applet. The preferred way to transfer control and begin working with Swing is to use invokeLater. The invokeLater method schedules a Runnable to be processed on the event dispatching thread.

You shouldn't create Swing components outside the EventDispatchThread because updating a component's model generates events, more here.

To deepen this answer may be enlightening.

As mentioned in comment to your question "paging" and maybe a "loading bar" may solve your problem.

Community
  • 1
  • 1
Luca Ricci
  • 95
  • 9