简体   繁体   中英

Lazy loading of jList in Swing with SwingWorker needs Thread.sleep()

I try to load content of a JList in Swing dynamically so that only shown content is loaded from somewhere (database, filesystem, rpc call). The code below does not implement this actions because it is not really important for showing the problem.

So I implement my own list model class:

class ServiceListModel extends AbstractListModel {


 private final static int MYSIZE = 500;
 private final List<String> delegate = new ArrayList<String>(); 


 public ServiceListModel() {
    // Init with dummy content
    for(int i=0;i<MYSIZE;i++) {
       delegate.add("Loading...");
    }
 }

 @Override
 public int getSize() {
    return delegate.size();
 }

 @Override
 public Object getElementAt(int index) {
    new DoSomeThingClass(index, this).execute();
 }


 private class DoSomeThingClass extends SwingWorker<String, String> {

    private int index;
    private ServiceListModel model;

    public DoSomeThingClass(int index, ServiceListModel model) {
        this.index = index;
        this.model = model;
    }

    @Override
    protected String doInBackground() throws Exception {
       System.out.println("BACKGROUND: " + index);
       // Do some stuff for updating content in JList
       return "";
    }

    @Override
    protected void process(java.util.List<String> list) {            
      for(String s: list) {

      }
    }

    @Override
    protected void done() {
       System.out.println("INDEX: " + index); 
    }
  }
}

Set the model in JList:

jList1.setModel(new ServiceListModel());

The problem is now that if I scroll quickly to the end of the JList content still all values are computed in method getElementAt(index) and not only the end of JList content. All index values are displayed in system out console.

To solve the problem it is needed to add a Thread.sleep(20) in getElementAt(index) before calling Swing Worker class.

Question:

Why did I need this Thread.sleep() call and is this not only a hack? I did not understand why getElementAt(index) is called for all values.

PS: The list model is only passed to swing worker class because of updating values which are calculated in doInBackground() method.

The getElementAt() is called several times because the size of the list is specified for 500 elements, and the list iterates over those elements.

Source from javax.swing.plaf.basic.BasicListUI:

for(int index = 0; index < dataModelSize; index++) {
    Object value = dataModel.getElementAt(index);
...

However I recommend to have a look at Glazed Lists . If you want to update elements at a given index you can use EventList.

"...You can populate your EventList from one thread and read it from another. For GUI applications, you can populate your EventList on a background thread while safely browsing it using the user-interface thread.."

Look at the tutorial , the issues browser might be a similar use case to yours.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM