Java 为什么在通过列表模型更新内容后,有时会得到空白的JLists?

Java 为什么在通过列表模型更新内容后,有时会得到空白的JLists?,java,swing,model,jlist,Java,Swing,Model,Jlist,我有一个反复出现的问题,我有一个JList,我希望用新内容更新它。我使用的是DefaultListModel,它提供了向列表中添加新内容的方法,但是当使用这些方法时,我发现一些调用会导致一个完全空白的JList。更新是否有效似乎是随机的,与发送的数据无关 下面是一个演示该问题的简单程序。它只是生成一个越来越大的列表来更新JList,但当运行时,列表内容似乎随机出现和消失 据我所知,我是按照正确的API来做这件事的,但我想我肯定缺少一些基本的东西 import java.awt.BorderLay

我有一个反复出现的问题,我有一个JList,我希望用新内容更新它。我使用的是DefaultListModel,它提供了向列表中添加新内容的方法,但是当使用这些方法时,我发现一些调用会导致一个完全空白的JList。更新是否有效似乎是随机的,与发送的数据无关

下面是一个演示该问题的简单程序。它只是生成一个越来越大的列表来更新JList,但当运行时,列表内容似乎随机出现和消失

据我所知,我是按照正确的API来做这件事的,但我想我肯定缺少一些基本的东西

import java.awt.BorderLayout;
import javax.swing.*;

public class ListUpdateTest extends JPanel {

    private JList list;
    private DefaultListModel model;

    public ListUpdateTest () {
        model = new DefaultListModel();
        list = new JList(model);

        setLayout(new BorderLayout());

        add(new JScrollPane(list),BorderLayout.CENTER);
        new UpdateRunner();
    }

    public void updateList (String [] entries) {
        model.removeAllElements();
        for (int i=0;i<entries.length;i++) {
            model.addElement(entries[i]);
        }
    }

    private class UpdateRunner implements Runnable {

        public UpdateRunner () {
            Thread t = new Thread(this);
            t.start();
        }

        public void run() {

            while (true) {
                int entryCount = model.size()+1;

                System.out.println("Should be "+entryCount+" entries");

                String [] entries = new String [entryCount];

                for (int i=0;i<entries.length;i++) {
                    entries[i] = "Entry "+i;
                }

                updateList(entries);

                try {
                    Thread.sleep(1000);
                } 
                catch (InterruptedException e) {}
            }
        }   
    }

    public static void main (String [] args) {

        JDialog dialog = new JDialog();
        dialog.setContentPane(new ListUpdateTest());
        dialog.setSize(200,400);
        dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
        dialog.setModal(true);
        dialog.setVisible(true);
        System.exit(0);
    }

}
导入java.awt.BorderLayout;
导入javax.swing.*;
公共类ListUpdateTest扩展了JPanel{
私人名单;
私有模型;
公共列表更新测试(){
model=新的DefaultListModel();
列表=新JList(型号);
setLayout(新的BorderLayout());
添加(新的JScrollPane(列表),BorderLayout.CENTER);
新的UpdateRunner();
}
public void updateList(字符串[]项){
model.removeAllElements();

对于(int i=0;i从未调用void updateList(…),但在内部我错过了
sleep(int)
,对于Swing,使用java.Swing.Timer是更好的,并且是必需的,您应该确保它在EDT上运行。 我想知道你没有注意到任何例外吗? 我第一次就得到了一个

要改为使用的代码(删除UpdateRunner并将其转换为javax.swing.Timer):

Timer t=new Timer(1000,new ActionListener(){
@凌驾
已执行的公共无效操作(操作事件e)
{
int entryCount=model.size()+1;
System.out.println(“应为“+入口计数+”条目”);
String[]entries=新字符串[entryCount];
对于(int i=0;i请看以下代码:

import java.awt.BorderLayout;
import javax.swing.*;
import javax.swing.SwingWorker;
import java.util.Arrays;
import java.util.List;
public class ListUpdateTest extends JPanel {

    private JList list;
    private DefaultListModel model;

    public ListUpdateTest () {
        model = new DefaultListModel();
        list = new JList(model);

        setLayout(new BorderLayout());

        add(new JScrollPane(list),BorderLayout.CENTER);
        (new UpdateRunner()).execute();
    }

    public void updateList (List<String> entries) {
        model.removeAllElements();
        for (String entry : entries) {
            model.addElement(entry);
        }
    }
    private class UpdateRunner extends SwingWorker<List<String>, List<String>>{

        @Override
        public List<String> doInBackground() {
            while (true) {
                int entryCount = model.size()+1;

                System.out.println("Should be "+entryCount+" entries");

                String [] entries = new String [entryCount];

                for (int i=0;i<entries.length;i++) {
                    entries[i] = "Entry "+i;
                }

                publish(Arrays.asList(entries));

                try {
                    Thread.sleep(1000);
                }
                catch (InterruptedException e) {}
            }
            return null;
        }
        @Override
        protected void process(List<List<String>> entries) {
            for (List<String> entry : entries) {
                updateList(entry);
            }
        }
        @Override
        protected void done() {
            updateList(Arrays.asList("done"));
        }
    }

    public static void main (String [] args) {

        JDialog dialog = new JDialog();
        dialog.setContentPane(new ListUpdateTest());
        dialog.setSize(200,400);
        dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
        dialog.setModal(true);
        dialog.setVisible(true);
        System.exit(0);
    }

}
导入java.awt.BorderLayout;
导入javax.swing.*;
导入javax.swing.SwingWorker;
导入java.util.array;
导入java.util.List;
公共类ListUpdateTest扩展了JPanel{
私人名单;
私有模型;
公共列表更新测试(){
model=新的DefaultListModel();
列表=新JList(型号);
setLayout(新的BorderLayout());
添加(新的JScrollPane(列表),BorderLayout.CENTER);
(新的UpdateRunner()).execute();
}
公共无效更新列表(列表条目){
model.removeAllElements();
for(字符串条目:条目){
模型.附录(条目);
}
}
私有类UpdateRunner扩展SwingWorker{
@凌驾
公共列表doInBackground(){
while(true){
int entryCount=model.size()+1;
System.out.println(“应为“+入口计数+”条目”);
String[]entries=新字符串[entryCount];

对于(int i=0;i,当试图在我的程序中实现上述答案时,它不起作用,因此我提出了下面的简单方法,添加到jList中,没有任何问题

public static void updateList (String entries, DefaultListModel model) {
    try {
        AddElement t = new AddElement(entries, model);
        t.sleep(100); t.stop();
    } catch (InterruptedException ex) {
        Logger.getLogger(Others.class.getName()).log(Level.SEVERE, null, ex);
    }
}

 static class AddElement extends Thread {

     public AddElement(String entries, DefaultListModel model) {
         model.addElement(entries);
     }

 }
要向模型中添加元素,只需执行此操作或在循环中调用updateList即可

int entryCount = model.size()+1; 
updateList("Entry "+entryCount, model);

jList中出现故障的实际原因是由于添加elemets的时间速率,因此为了避免出现问题,我在上面的代码中使用的时间缩短了不到1秒t.sleep(100)而且效果很好。较低的线程延迟可能会导致小故障

是的,但会以一种非常复杂的方式出现。但是你是对的,更新列表应该在
EDT
+1上完成。计时器在swing重绘线程中运行,因此,每次触发时都会正确更新UI。我同意@sthupahsmat+1用于answer、 +1,虽然我的示例只使用了一个简单的计时器,但在我的实际代码中,我需要一个单独的线程来进行更新,因为它以更复杂的方式收集数据。是否有一个等效于计时器的线程来创建一个与Swing更新机制不冲突的单独线程?您必须查找@gasan发布的SwingWorker,但请注意ecutor+SwingWorker for Java是的,但是睡眠不会影响EDT或主线程,它会暂停Swing Worker线程。因此没有冻结或空屏幕。+1我相信这就是如何正确地委托这样一个工作流。这似乎正是我想要的。我必须承认,我没有看到从不同线程更新Swing的问题,但是我会详细了解秋千线的工作原理。谢谢。
int entryCount = model.size()+1; 
updateList("Entry "+entryCount, model);