我尝试动态加载Swing中JList的内容,以便只从某处(数据库,文件系统,rpc调用)加载显示的内容。下面的代码没有实现此操作,因为它对于显示问题并不重要。
所以我实现了自己的列表模型类:
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);
}
}
}
在JList中设置模型:
jList1.setModel(new ServiceListModel());
现在的问题是,如果我快速滚动到JList内容的末尾,仍然会在方法getElementAt(index)
中计算所有值,而不仅仅是JList内容的结尾。 所有索引值都显示在system out console中。
要解决此问题,需要在调用Swing Worker类之前在getElementAt(index)
中添加Thread.sleep(20)。
问题:
为什么我需要这个Thread.sleep()调用,这不仅仅是一个黑客攻击吗?我不明白为什么要为所有值调用getElementAt(index)
。
P.S:列表模型仅传递给swing worker类,因为更新了以doInBackground()
方法计算的值。
答案 0 :(得分:1)
多次调用getElementAt()因为为500个元素指定了列表的大小,并且列表会迭代这些元素。
来自javax.swing.plaf.basic.BasicListUI的来源:
for(int index = 0; index < dataModelSize; index++) {
Object value = dataModel.getElementAt(index);
...
但我建议您查看Glazed Lists。如果要更新给定索引处的元素,可以使用EventList。
“...您可以从一个线程填充EventList并从另一个线程中读取它。对于GUI应用程序,您可以在后台线程上填充EventList,同时使用用户界面线程安全地浏览它。”
查看tutorial,问题浏览器可能与您的用例类似。