简体   繁体   English

使用SwingWorker在Swing中延迟加载jList需要Thread.sleep()

[英]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). 我尝试在Swing中动态加载JList的内容,以便仅从某处(数据库,文件系统,rpc调用)加载显示的内容。 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: 在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. 现在的问题是,如果我快速滚动到JList内容的末尾,那么所有值仍然在方法getElementAt(index)中计算,而不仅是JList内容的末尾。 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. 为了解决该问题,需要在调用Swing Worker类之前在getElementAt(index)添加Thread.sleep(20)。

Question: 题:

Why did I need this Thread.sleep() call and is this not only a hack? 为什么我需要这个Thread.sleep()调用,这不仅是hack吗? I did not understand why getElementAt(index) is called for all values. 我不明白为什么要为所有值调用getElementAt(index)

PS: The list model is only passed to swing worker class because of updating values which are calculated in doInBackground() method. PS:由于更新了在doInBackground()方法中计算的值,因此列表模型仅传递给swing工人类。

The getElementAt() is called several times because the size of the list is specified for 500 elements, and the list iterates over those elements. 由于为500个元素指定了列表的大小,因此getElementAt()被多次调用,并且列表在这些元素上进行迭代。

Source from javax.swing.plaf.basic.BasicListUI: 来自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. 如果要更新给定索引处的元素,则可以使用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.." “ ...您可以从一个线程填充EventList并从另一个线程读取它。对于GUI应用程序,您可以在后台线程中填充EventList,同时使用用户界面线程安全地浏览它。

Look at the tutorial , the issues browser might be a similar use case to yours. 查看教程 ,问题浏览器可能与您的用例相似。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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